package sudoku.util.game;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import sudoku.data.ForceChainButton;
import sudoku.data.ForceChainButton.Candidate;
import sudoku.data.ForceChainButton.FilterCandidate;
import sudoku.data.SolverButton;
import sudoku.data.SudokuButton;
import sudoku.model.SudokuModel;
import sudoku.util.Config;

/**
 * @author Romet Piho
 * 
 */
public class Solver {

  private volatile SudokuModel model;

  private volatile Config config;

  private int ruut;

  private int kast;

  /**
   * eemaldatavad nupud
   */
  private List<List<SolverButton>> sammud;

  private List<List<SudokuButton>> solverSeotud;

  /**
   * tehnikate nimed
   */
  private List<String> tehnikad;

  /**
   * kas toimub eemaldamine
   */
  private boolean removing;

  private List<Integer> aste;

  private int difficulty;

  private int maxtehnika;

  /**
   * list, kus on kandidaadid, mille korral tehti mitu ahelat. Listis on
   * kandidaadi number 0 - (ruut-1)
   */
  private List<Integer> multiColorKandidaadid;

  public Solver(Config config, SudokuModel model, int ruut, int kast) {
    this.config = config;
    this.model = model;
    this.ruut = ruut;
    this.kast = kast;
    resetAllKandidaadid();
    resetAllSeotud();
    setDefaultKandidaadid();
    sammud = new ArrayList<List<SolverButton>>();
    tehnikad = new ArrayList<String>();
    removing = false;
    maxtehnika = 0;
  }

  public Solver(Config config, SudokuModel model, int ruut, int kast, boolean niisama) {
    this.config = config;
    this.model = model;
    this.ruut = ruut;
    this.kast = kast;
    if (niisama) {
      resetAllKandidaadid();
      setDefaultKandidaadid();
    }
  }

  public int getDifficulty() {
    return difficulty;
  }

  /**
   * tagastab kõik antud värvigrupi nupud sudoku buddonite listina
   * 
   * @param kan
   *          antud kandidaat
   * @param col
   *          väiksem värvigrupi number
   * @return
   */
  private List<SudokuButton> getColorButtons(int kan, int col) {
    List<SudokuButton> list3 = new ArrayList<SudokuButton>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
          if (model.getSudokuButtons()[i][j].getColor(kan) == col || model.getSudokuButtons()[i][j].getColor(kan) == (col + 1)) {
            list3.add(model.getSudokuButtons()[i][j]);
          }
        }
      }
    }
    return list3;
  }

  /**
   * tagastab kõik antud kandidaadi antud värvi nupud solverbuttonite listina
   * 
   * @param kan
   *          antud kandidaat
   * @param col
   *          värvi number
   * @return
   */
  private List<SolverButton> getColorButtonsSolverButtons(int kan, int col, int level) {
    List<SolverButton> list2 = new ArrayList<SolverButton>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)
            && model.getSudokuButtons()[i][j].getColor(kan) == col) {
          list2.add(new SolverButton(i, j, kan, level));
        }
      }
    }
    return list2;
  }

  /**
   * tagastab kõik antud kandidaadi antud värvi nuppude solverbuttonite listi
   * 
   * @param kan
   * @param col
   * @return
   */
  private List<SolverButton> getColorRemoveButtons(int kan, int col, int level) {
    List<SolverButton> list2 = new ArrayList<SolverButton>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
          if (model.getSudokuButtons()[i][j].getColor(kan) == col) {
            list2.add(new SolverButton(i, j, kan, level));
          }
        }
      }
    }
    return list2;
  }

  /**
   * tagastab listi kõikidest antud nupuga seotud nuppudest, mille number on kan
   * 
   * @param kan
   * @param b
   * @return
   */
  private List<SudokuButton> getDependences(int kan, SudokuButton b) {
    List<SudokuButton> list = new ArrayList<SudokuButton>();
    List<String> kohalist = new ArrayList<String>();
    int rida = 0;
    int veerg = 0;
    if (b.getI() > (kast - 1) && b.getI() < (kast * 2)) {
      rida = kast;
    }
    if (b.getI() > (kast * 2 - 1) && b.getI() < (kast * 3)) {
      rida = kast * 2;
    }
    if (b.getI() > (kast * 3 - 1) && b.getI() < (kast * 4)) {
      rida = kast * 3;
    }
    if (b.getJ() > (kast - 1) && b.getJ() < (kast * 2)) {
      veerg = kast;
    }
    if (b.getJ() > (kast * 2 - 1) && b.getJ() < (kast * 3)) {
      veerg = kast * 2;
    }
    if (b.getJ() > (kast * 3 - 1) && b.getJ() < (kast * 4)) {
      veerg = kast * 3;
    }
    for (int k = rida; k < (rida + kast); k++) {
      for (int l = veerg; l < (veerg + kast); l++) {
        try {
          int a = Integer.parseInt(model.getSudokuButtons()[k][l].getNumber()) - 1;
          if (a == kan) {
            list.add(model.getSudokuButtons()[k][l]);
            kohalist.add(b.getI() + "," + b.getJ());
          }
        } catch (Exception er) {
        }
      }
    }
    for (int k = 0; k < ruut; k++) {
      try {
        int a = Integer.parseInt(model.getSudokuButtons()[b.getI()][k].getNumber()) - 1;
        if (a == kan && !kohalist.contains(b.getI() + "," + b.getJ())) {
          list.add(model.getSudokuButtons()[b.getI()][k]);
        }
      } catch (Exception er) {
      }
      try {
        int a = Integer.parseInt(model.getSudokuButtons()[k][b.getJ()].getNumber()) - 1;
        if (a == kan && !kohalist.contains(b.getI() + "," + b.getJ())) {
          list.add(model.getSudokuButtons()[k][b.getJ()]);
        }
      } catch (Exception er) {
      }
    }
    return list;
  }

  /**
   * tagastab antud nupuga seotud nuppude kõikide värvide listi
   * 
   * @param i
   * @param j
   * @param kan
   * @return
   */
  private List<Integer> getDependentColors(int i, int j, int kan) {
    List<Integer> list = new ArrayList<Integer>();
    int rida = (i / kast) * kast;
    int veerg = (j / kast) * kast;
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan)
          && model.getSudokuButtons()[i][l].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[i][l].getColor(kan)));
      }
    }
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[l][j].getNumber().equals(" ") && model.getSudokuButtons()[l][j].getKandidaat(kan)
          && model.getSudokuButtons()[l][j].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[l][j].getColor(kan)));
      }
    }
    for (int l = rida; l < (rida + kast); l++) {
      for (int m = veerg; m < (veerg + kast); m++) {
        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)
            && model.getSudokuButtons()[l][m].getColor(kan) != -1) {
          list.add(new Integer(model.getSudokuButtons()[l][m].getColor(kan)));
        }
      }
    }
    return list;
  }

  /**
   * tagastab antud nupuga rea või veeruga seotud nuppude kõikide värvide listi
   * 
   * @param i
   * @param j
   * @param kan
   * @return
   */
  private List<Integer> getDependentRowColColors(int i, int j, int kan) {
    List<Integer> list = new ArrayList<Integer>();
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan)
          && model.getSudokuButtons()[i][l].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[i][l].getColor(kan)));
      }
    }
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[l][j].getNumber().equals(" ") && model.getSudokuButtons()[l][j].getKandidaat(kan)
          && model.getSudokuButtons()[l][j].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[l][j].getColor(kan)));
      }
    }
    return list;
  }

  /**
   * tagastab antud nupuga rea või kastiga seotud nuppude kõikide värvide listi
   * 
   * @param i
   * @param j
   * @param kan
   * @return
   */
  private List<Integer> getDependentRowBoxColors(int i, int j, int kan) {
    List<Integer> list = new ArrayList<Integer>();
    int rida = (i / kast) * kast;
    int veerg = (j / kast) * kast;
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan)
          && model.getSudokuButtons()[i][l].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[i][l].getColor(kan)));
      }
    }
    for (int l = rida; l < (rida + kast); l++) {
      for (int m = veerg; m < (veerg + kast); m++) {
        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)
            && model.getSudokuButtons()[l][m].getColor(kan) != -1) {
          list.add(new Integer(model.getSudokuButtons()[l][m].getColor(kan)));
        }
      }
    }
    return list;
  }

  /**
   * tagastab antud nupuga veeru või kastiga seotud nuppude kõikide värvide
   * listi
   * 
   * @param i
   * @param j
   * @param kan
   * @return
   */
  private List<Integer> getDependentColBoxColors(int i, int j, int kan) {
    List<Integer> list = new ArrayList<Integer>();
    int rida = (i / kast) * kast;
    int veerg = (j / kast) * kast;
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[l][j].getNumber().equals(" ") && model.getSudokuButtons()[l][j].getKandidaat(kan)
          && model.getSudokuButtons()[l][j].getColor(kan) != -1) {
        list.add(new Integer(model.getSudokuButtons()[l][j].getColor(kan)));
      }
    }
    for (int l = rida; l < (rida + kast); l++) {
      for (int m = veerg; m < (veerg + kast); m++) {
        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)
            && model.getSudokuButtons()[l][m].getColor(kan) != -1) {
          list.add(new Integer(model.getSudokuButtons()[l][m].getColor(kan)));
        }
      }
    }
    return list;
  }

  public int getMaxtehnika() {
    return maxtehnika;
  }

  /**
   * @param kan1
   *          otsitav kandidaat
   * @param col1
   *          esimene värv
   * @param col2
   *          teine värv
   * @return tagastab, kas antud värvide paarilsed on kusagil seotud
   */
  private boolean getMulticolorDependences(int kan, int col1, int col2) {
    int c1 = col1 % 2 == 0 ? col1 - 1 : col1 + 1;
    int c2 = col2 % 2 == 0 ? col2 - 1 : col2 + 1;
    for (int i = 0; i < ruut; i++) {
      boolean reas1 = false;
      boolean reas2 = false;
      boolean veerus1 = false;
      boolean veerus2 = false;
      boolean kastis1 = false;
      boolean kastis2 = false;
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
          if (model.getSudokuButtons()[i][j].getColor(kan) == c1) {
            reas1 = true;
          }
          if (model.getSudokuButtons()[i][j].getColor(kan) == c2) {
            reas2 = true;
          }
        }
        if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaat(kan)) {
          if (model.getSudokuButtons()[j][i].getColor(kan) == c1) {
            veerus1 = true;
          }
          if (model.getSudokuButtons()[j][i].getColor(kan) == c2) {
            veerus2 = true;
          }
        }
      }
      int rida = (i / kast) * kast;
      int veerg = (i % kast) * kast;
      for (int m = rida; m < (rida + kast); m++) {
        for (int n = veerg; n < (veerg + kast); n++) {
          if (model.getSudokuButtons()[m][n].getNumber().equals(" ") && model.getSudokuButtons()[m][n].getKandidaat(kan)) {
            if (model.getSudokuButtons()[m][n].getColor(kan) == c1) {
              kastis1 = true;
            }
            if (model.getSudokuButtons()[m][n].getColor(kan) == c2) {
              kastis2 = true;
            }
          }
        }
      }
      if ((reas1 && reas2) || (veerus1 && veerus2) || (kastis1 && kastis2)) {
        return true;
      }
    }
    return false;
  }

  private boolean getMulticolorDependences(int kan, Integer col1, Integer col2) {
    return this.getMulticolorDependences(kan, col1.intValue(), col2.intValue());
  }

  private SudokuButton leitud(List<List<SolverButton>> listid, List<List<SudokuButton>> levellist, List<List<SolverButton>> levellist2,
      String tekst, int level, int diff) {
    SudokuButton button2 = level17(listid);
    if (button2 != null && !removing && levellist.size() > 0) {
      for (int i = 0; i < levellist.size(); i++) {
        sammud.add(levellist2.get(i));
        tehnikad.add(tekst);
        button2.add(levellist.get(i));
        if (config.isDebug() && !model.isGenerating()) {
          Config.log(tekst);
        }
      }
    }
    difficulty += diff;
    if (maxtehnika < level) {
      maxtehnika = level;
    }
    return button2;
  }

  /**
   * Singles
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level1(List<List<SolverButton>> listid) {
    int diff = 4;
    int level = 1;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
          if (model.getSudokuButtons()[i][j].getKandidaate() == 1) {
            List<SolverButton> list2 = new ArrayList<SolverButton>();
            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
            list3.add(model.getSudokuButtons()[i][j]);
            list2.add(new SolverButton(i, j, model.getSudokuButtons()[i][j].getKandidaat(), level));
            levellist.add(list3);
            levellist2.add(list2);
            if (!removing) {
              sammud.add(levellist2.get(0));
              tehnikad.add("Single");
              model.getSudokuButtons()[i][j].add(levellist.get(0));
              if (config.isDebug() && !model.isGenerating()) {
                Config.log("Single");
              }
            }
            if (maxtehnika < 1) {
              maxtehnika = 1;
            }
            aste.add(new Integer(level));
            difficulty += diff;
            return model.getSudokuButtons()[i][j];
          }
        }
      }
    }
    return null;
  }

  /**
   * Hidden Singles
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level2(List<List<SolverButton>> listid) {
    int diff = 10;
    int level = 2;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    SudokuButton button = level1(listid);
    if (button != null) {
      return button;
    }
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() > 1) {
          int rida = 0;
          int veerg = 0;
          if (i > (kast - 1) && i < (kast * 2)) {
            rida = kast;
          }
          if (i > (kast * 2 - 1) && i < (kast * 3)) {
            rida = kast * 2;
          }
          if (i > (kast * 3 - 1) && i < (kast * 4)) {
            rida = kast * 3;
          }
          if (j > (kast - 1) && j < (kast * 2)) {
            veerg = kast;
          }
          if (j > (kast * 2 - 1) && j < (kast * 3)) {
            veerg = kast * 2;
          }
          if (j > (kast * 3 - 1) && j < (kast * 4)) {
            veerg = kast * 3;
          }
          for (int k = 0; k < ruut; k++) {
            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
            if (model.getSudokuButtons()[i][j].getKandidaat(k)) {
              int reas = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(k)) {
                  reas++;
                }
              }
              if (reas == 1 && !removing) {
                for (int l = 0; l < ruut; l++) {
                  if (model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                    List<SudokuButton> list = getDependences(k, model.getSudokuButtons()[i][l]);
                    for (int index = 0; index < list.size(); index++) {
                      list3.add(list.get(index));
                    }
                  }
                }
              }
              int veerus = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[l][j].getNumber().equals(" ") && model.getSudokuButtons()[l][j].getKandidaat(k)) {
                  veerus++;
                }
              }
              if (veerus == 1 && !removing) {
                for (int l = 0; l < ruut; l++) {
                  if (model.getSudokuButtons()[l][j].getNumber().equals(" ")) {
                    List<SudokuButton> list = getDependences(k, model.getSudokuButtons()[l][j]);
                    for (int index = 0; index < list.size(); index++) {
                      list3.add(list.get(index));
                    }
                  }
                }
              }
              int kastis = 0;
              for (int l = rida; l < (rida + kast); l++) {
                for (int m = veerg; m < (veerg + kast); m++) {
                  if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
                    kastis++;
                  }
                }
              }
              if (kastis == 1 && !removing) {
                for (int l = rida; l < (rida + kast); l++) {
                  for (int m = veerg; m < (veerg + kast); m++) {
                    if (model.getSudokuButtons()[l][m].getNumber().equals(" ")) {
                      List<SudokuButton> list = getDependences(k, model.getSudokuButtons()[l][m]);
                      for (int index = 0; index < list.size(); index++) {
                        list3.add(list.get(index));
                      }
                    }
                  }
                }
              }
              if (reas == 1 || veerus == 1 || kastis == 1) {
                List<SolverButton> list2 = new ArrayList<SolverButton>();
                boolean[] bool = model.getSudokuButtons()[i][j].getKandidaadid();
                for (int kan = 0; kan < ruut; kan++) {
                  if (bool[kan] && kan != k) {
                    model.getSudokuButtons()[i][j].removeKandidaat(kan);
                    list2.add(new SolverButton(i, j, kan, level));
                  }
                }
                list3.add(model.getSudokuButtons()[i][j]);
                levellist.add(list3);
                levellist2.add(list2);
                if (!removing) {
                  sammud.add(levellist2.get(0));
                  tehnikad.add("Hidden single");
                  model.getSudokuButtons()[i][j].add(levellist.get(0));
                  if (config.isDebug() && !model.isGenerating()) {
                    Config.log("Hidden single");
                  }
                }
                aste.add(new Integer(level));
                difficulty += diff;
                if (maxtehnika < 2) {
                  maxtehnika = 2;
                }
                return model.getSudokuButtons()[i][j];
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Locked Candidates 1
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level3(List<List<SolverButton>> listid) {
    int diff = 50;
    SudokuButton button = level2(listid);
    int level = 3;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int index = 0; index < ruut; index++) {
      int i = index / kast;
      int j = index % kast;
      for (int kan = 0; kan < ruut; kan++) {
        int reas = 0;
        int veerus = 0;
        int r1 = -1, r2 = -1, r3 = -1, r4 = -1, v1 = -1, v2 = -1, v3 = -1, v4 = -1;
        for (int k = i * kast; k < (i + 1) * kast; k++) {
          for (int l = j * kast; l < (j + 1) * kast; l++) {
            if (model.getSudokuButtons()[k][l].getNumber().equals(" ") && model.getSudokuButtons()[k][l].getKandidaat(kan)) {
              if (r1 != k && r2 != k && r3 != k && r4 != k) {
                reas++;
                if (r1 == -1) {
                  r1 = k;
                } else if (r2 == -1) {
                  r2 = k;
                } else if (r3 == -1) {
                  r3 = k;
                } else {
                  r4 = k;
                }
              }
              if (v1 != l && v2 != l && v3 != l && v4 != l) {
                veerus++;
                if (v1 == -1) {
                  v1 = l;
                } else if (v2 == -1) {
                  v2 = l;
                } else if (v3 == -1) {
                  v3 = l;
                } else {
                  v4 = l;
                }
              }
            }
          }
        }
        if (reas == 1) {
          for (int k = i * kast; k < (i + 1) * kast; k++) {
            for (int l = j * kast; l < (j + 1) * kast; l++) {
              if (k != r1 && model.getSudokuButtons()[k][l].getNumber().equals(" ") && model.getSudokuButtons()[k][l].getKandidaat(kan)) {
                reas++;
              }
            }
          }
          if (reas > 1) {
            List<Integer> koht = new ArrayList<Integer>();
            reas = 0;
            for (int k = 0; k < ruut; k++) {
              if (k >= j * kast && k < (j + 1) * kast) {
                if (model.getSudokuButtons()[r1][k].getNumber().equals(" ")) {
                  reas++;
                  for (int a = 0; a < ruut; a++) {
                    if (model.getSudokuButtons()[r1][k].getKandidaat(a) && !koht.contains(new Integer(a))) {
                      koht.add(new Integer(a));
                    }
                  }
                }
              }
            }
            if (koht.size() > reas) {
              boolean b = false;
              boolean temp = eemaldatud;
              List<SolverButton> list2 = new ArrayList<SolverButton>();
              for (int k = 0; k < ruut; k++) {
                if (k < j * kast || k >= (j + 1) * kast) {
                  if (model.getSudokuButtons()[r1][k].getNumber().equals(" ") && model.getSudokuButtons()[r1][k].getKandidaat(kan)) {
                    model.getSudokuButtons()[r1][k].removeKandidaat(kan);
                    list2.add(new SolverButton(r1, k, kan, level));
                    b = true;
                    eemaldatud = true;
                  }
                }
              }
              if (b) {
                if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                  for (int k = 0; k < ruut; k++) {
                    if (k >= j * kast && k < (j + 1) * kast) {
                      if (model.getSudokuButtons()[r1][k].getNumber().equals(" ") && model.getSudokuButtons()[r1][k].getKandidaat(kan)) {
                        list3.add(model.getSudokuButtons()[r1][k]);
                      }
                    }
                  }
                  if (!removing || solverSeotud.contains(list3)) {
                    levellist.add(list3);
                    levellist2.add(list2);
                    aste.add(new Integer(level));
                  } else {
                    eemaldatud = temp;
                    for (int tempindex = 0; tempindex < list2.size(); tempindex++) {
                      SolverButton butt = list2.get(tempindex);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                } else {
                  eemaldatud = temp;
                  for (int tempindex = 0; tempindex < list2.size(); tempindex++) {
                    SolverButton butt = list2.get(tempindex);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                  }
                }
                if (eemaldatud) {
                  return leitud(listid, levellist, levellist2, "Locked candidates 1", level, diff);
                }
              }
            }
          }
        }
        if (veerus == 1) {
          for (int k = i * kast; k < (i + 1) * kast; k++) {
            for (int l = j * kast; l < (j + 1) * kast; l++) {
              if (l != v1 && model.getSudokuButtons()[k][l].getNumber().equals(" ") && model.getSudokuButtons()[k][l].getKandidaat(kan)) {
                veerus++;
              }
            }
          }
          if (veerus > 1) {
            veerus = 0;
            List<Integer> koht = new ArrayList<Integer>();
            for (int k = 0; k < ruut; k++) {
              if (k >= i * kast && k < (i + 1) * kast) {
                if (model.getSudokuButtons()[k][v1].getNumber().equals(" ")) {
                  veerus++;
                  for (int a = 0; a < ruut; a++) {
                    if (model.getSudokuButtons()[k][v1].getKandidaat(a) && !koht.contains(new Integer(a))) {
                      koht.add(new Integer(a));
                    }
                  }
                }
              }
            }
            if (koht.size() > veerus) {
              boolean b = false;
              boolean temp = eemaldatud;
              List<SolverButton> list2 = new ArrayList<SolverButton>();
              for (int k = 0; k < ruut; k++) {
                if (k < i * kast || k >= (i + 1) * kast) {
                  if (model.getSudokuButtons()[k][v1].getNumber().equals(" ") && model.getSudokuButtons()[k][v1].getKandidaat(kan)) {
                    model.getSudokuButtons()[k][v1].removeKandidaat(kan);
                    list2.add(new SolverButton(k, v1, kan, level));
                    b = true;
                    eemaldatud = true;
                  }
                }
              }
              if (b) {
                if (!removing || (!listid.contains(list2) && sammud.contains(list2)) || sammud.contains(list2)) {
                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                  for (int k = 0; k < ruut; k++) {
                    if (k >= i * kast && k < (i + 1) * kast) {
                      if (model.getSudokuButtons()[k][v1].getNumber().equals(" ") && model.getSudokuButtons()[k][v1].getKandidaat(kan)) {
                        list3.add(model.getSudokuButtons()[k][v1]);
                      }
                    }
                  }
                  if (!removing || solverSeotud.contains(list3)) {
                    levellist.add(list3);
                    levellist2.add(list2);
                    aste.add(new Integer(level));
                  } else {
                    eemaldatud = temp;
                    for (int tempindex = 0; tempindex < list2.size(); tempindex++) {
                      SolverButton butt = list2.get(tempindex);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                } else {
                  eemaldatud = temp;
                  for (int tempindex = 0; tempindex < list2.size(); tempindex++) {
                    SolverButton butt = list2.get(tempindex);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                  }
                }
                if (eemaldatud) {
                  return leitud(listid, levellist, levellist2, "Locked candidates 1", level, diff);
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * 
   * Naked Pairs
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level4(List<List<SolverButton>> listid) {
    int diff = 60;
    SudokuButton button = level3(listid);
    int level = 4;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;

    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() == 2) {
          for (int k = j; k < ruut; k++) {
            if (k != j && model.getSudokuButtons()[i][k].getNumber().equals(" ") && model.getSudokuButtons()[i][k].getKandidaate() == 2) {
              List<Integer> list = new ArrayList<Integer>();
              for (int kan = 0; kan < ruut; kan++) {
                if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                  list.add(new Integer(kan));
                }
                if (model.getSudokuButtons()[i][k].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                  list.add(new Integer(kan));
                }
              }
              if (list.size() == 2) {
                boolean b = false;
                boolean temp = eemaldatud;
                List<SolverButton> list2 = new ArrayList<SolverButton>();
                for (int l = 0; l < ruut; l++) {
                  if (l != j && l != k && model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                    for (int kan = 0; kan < list.size(); kan++) {
                      if (model.getSudokuButtons()[i][l].getKandidaat(list.get(kan))) {
                        model.getSudokuButtons()[i][l].removeKandidaat(list.get(kan));
                        list2.add(new SolverButton(i, l, list.get(kan), level));
                        b = true;
                        eemaldatud = true;
                      }
                    }
                  }
                }
                if (b) {
                  if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                    List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                    list3.add(model.getSudokuButtons()[i][j]);
                    list3.add(model.getSudokuButtons()[i][k]);
                    if (!removing || solverSeotud.contains(list3)) {
                      levellist.add(list3);
                      levellist2.add(list2);
                      aste.add(new Integer(level));
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                  } else {
                    eemaldatud = temp;
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                  if (eemaldatud) {
                    return leitud(listid, levellist, levellist2, "Naked pair", level, diff);
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() == 2) {
          for (int k = i; k < ruut; k++) {
            if (k != i && model.getSudokuButtons()[k][j].getNumber().equals(" ") && model.getSudokuButtons()[k][j].getKandidaate() == 2) {
              List<Integer> list = new ArrayList<Integer>();
              for (int kan = 0; kan < ruut; kan++) {
                if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                  list.add(new Integer(kan));
                }
                if (model.getSudokuButtons()[k][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                  list.add(new Integer(kan));
                }
              }
              if (list.size() == 2) {
                boolean b = false;
                boolean temp = eemaldatud;
                List<SolverButton> list2 = new ArrayList<SolverButton>();
                for (int l = 0; l < ruut; l++) {
                  if (l != i && l != k && model.getSudokuButtons()[l][j].getNumber().equals(" ")) {
                    for (int kan = 0; kan < list.size(); kan++) {
                      if (model.getSudokuButtons()[l][j].getKandidaat(list.get(kan))) {
                        model.getSudokuButtons()[l][j].removeKandidaat(list.get(kan));
                        list2.add(new SolverButton(l, j, list.get(kan), level));
                        b = true;
                        eemaldatud = true;
                      }
                    }
                  }
                }
                if (b) {
                  if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                    List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                    list3.add(model.getSudokuButtons()[i][j]);
                    list3.add(model.getSudokuButtons()[k][j]);
                    if (!removing || solverSeotud.contains(list3)) {
                      levellist.add(list3);
                      levellist2.add(list2);
                      aste.add(new Integer(level));
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                  } else {
                    eemaldatud = temp;
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                  if (eemaldatud) {
                    return leitud(listid, levellist, levellist2, "Naked pair", level, diff);
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() == 2) {
          int rida1 = (i / kast) * kast;
          int veerg1 = (j / kast) * kast;
          for (int k = i; k < (rida1 + kast); k++) {
            for (int l = veerg1; l < (veerg1 + kast); l++) {
              if ((k > i || l > j) && model.getSudokuButtons()[k][l].getNumber().equals(" ")
                  && model.getSudokuButtons()[k][l].getKandidaate() == 2) {
                List<Integer> list = new ArrayList<Integer>();
                for (int kan = 0; kan < ruut; kan++) {
                  if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                    list.add(new Integer(kan));
                  }
                  if (model.getSudokuButtons()[k][l].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                    list.add(new Integer(kan));
                  }
                }
                if (list.size() == 2) {
                  boolean b = false;
                  boolean temp = eemaldatud;
                  List<SolverButton> list2 = new ArrayList<SolverButton>();
                  for (int m = rida1; m < (rida1 + kast); m++) {
                    for (int n = veerg1; n < (veerg1 + kast); n++) {
                      if (!(m == i && n == j) && !(m == k && n == l) && model.getSudokuButtons()[m][n].getNumber().equals(" ")) {
                        for (int kan = 0; kan < list.size(); kan++) {
                          if (model.getSudokuButtons()[m][n].getKandidaat(list.get(kan))) {
                            model.getSudokuButtons()[m][n].removeKandidaat(list.get(kan));
                            list2.add(new SolverButton(m, n, list.get(kan), level));
                            b = true;
                            eemaldatud = true;
                          }
                        }

                      }
                    }
                  }
                  if (b) {
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                      list3.add(model.getSudokuButtons()[i][j]);
                      list3.add(model.getSudokuButtons()[k][l]);
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Naked pair", level, diff);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Locked Candidates 2
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level5(List<List<SolverButton>> listid) {
    int diff = 60;
    SudokuButton button = level4(listid);
    int level = 5;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int kan = 0; kan < ruut; kan++) {
        int reas = 0;
        int veerus = 0;
        int r1 = -1, r2 = -1, v1 = -1, v2 = -1;
        for (int j = 0; j < ruut; j++) {
          if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
            int kastis = (j / kast) * kast;
            if (r1 != kastis && r2 != kastis) {
              reas++;
              if (r1 == -1) {
                r1 = kastis;
              } else {
                r2 = kastis;
              }
            }
          }
          if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaat(kan)) {
            int kastis = (j / kast) * kast;
            if (v1 != kastis && v2 != kastis) {
              veerus++;
              if (v1 == -1) {
                v1 = kastis;
              } else {
                v2 = kastis;
              }
            }
          }
        }
        if (reas == 1) {
          boolean b = false;
          boolean temp = eemaldatud;
          List<SolverButton> list2 = new ArrayList<SolverButton>();
          int rida = (i / kast) * kast;
          for (int l = rida; l < (rida + kast); l++) {
            for (int m = r1; m < (r1 + kast); m++) {
              if (l != i && model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)) {
                model.getSudokuButtons()[l][m].removeKandidaat(kan);
                list2.add(new SolverButton(l, m, kan, level));
                b = true;
                eemaldatud = true;
              }
            }
          }
          if (b) {
            if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
              List<SudokuButton> list3 = new ArrayList<SudokuButton>();
              for (int l = rida; l < (rida + kast); l++) {
                for (int m = r1; m < (r1 + kast); m++) {
                  if (l == i && model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)) {
                    list3.add(model.getSudokuButtons()[l][m]);
                  }
                }
              }
              List<Integer> list = new ArrayList<Integer>();
              for (int java = 0; java < list3.size(); java++) {
                SudokuButton bu = list3.get(java);
                for (int index = 0; index < ruut; index++) {
                  if (bu.getKandidaat(index) && !list.contains(new Integer(index))) {
                    list.add(new Integer(index));
                  }
                }
              }
              boolean c = list.size() == 2;
              if (c) {
                eemaldatud = temp;
                for (int java = 0; java < list2.size(); java++) {
                  SolverButton butt = list2.get(java);
                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                }
              } else {
                if (!removing || solverSeotud.contains(list3)) {
                  levellist.add(list3);
                  levellist2.add(list2);
                  aste.add(new Integer(level));
                } else {
                  eemaldatud = temp;
                  for (int java = 0; java < list2.size(); java++) {
                    SolverButton butt = list2.get(java);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                  }
                }
              }
            } else {
              eemaldatud = temp;
              for (int java = 0; java < list2.size(); java++) {
                SolverButton butt = list2.get(java);
                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              }
            }
            if (eemaldatud) {
              return leitud(listid, levellist, levellist2, "Locked candidates 2", level, diff);
            }
          }
        }
        if (veerus == 1) {
          boolean b = false;
          boolean temp = eemaldatud;
          List<SolverButton> list2 = new ArrayList<SolverButton>();
          int veerg = (i / kast) * kast;
          for (int l = v1; l < (v1 + kast); l++) {
            for (int m = veerg; m < (veerg + kast); m++) {
              if (m != i && model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)) {
                model.getSudokuButtons()[l][m].removeKandidaat(kan);
                list2.add(new SolverButton(l, m, kan, level));
                b = true;
                eemaldatud = true;
              }
            }
          }
          if (b) {
            if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
              List<SudokuButton> list3 = new ArrayList<SudokuButton>();
              for (int l = v1; l < (v1 + kast); l++) {
                for (int m = veerg; m < (veerg + kast); m++) {
                  if (m == i && model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)) {
                    list3.add(model.getSudokuButtons()[l][m]);
                  }
                }
              }
              List<Integer> list = new ArrayList<Integer>();
              for (int java = 0; java < list3.size(); java++) {
                SudokuButton bu = list3.get(java);
                for (int index = 0; index < ruut; index++) {
                  if (bu.getKandidaat(index) && !list.contains(new Integer(index))) {
                    list.add(new Integer(index));
                  }
                }
              }
              boolean c = list.size() == 2;
              if (c) {
                eemaldatud = temp;
                for (int java = 0; java < list2.size(); java++) {
                  SolverButton butt = list2.get(java);
                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                }
              } else {
                if (!removing || solverSeotud.contains(list3)) {
                  levellist.add(list3);
                  levellist2.add(list2);
                  aste.add(new Integer(level));
                } else {
                  eemaldatud = temp;
                  for (int java = 0; java < list2.size(); java++) {
                    SolverButton butt = list2.get(java);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                  }
                }
              }
            } else {
              eemaldatud = temp;
              for (int java = 0; java < list2.size(); java++) {
                SolverButton butt = list2.get(java);
                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              }
            }
            if (eemaldatud) {
              return leitud(listid, levellist, levellist2, "Locked candidates 2", level, diff);
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Naked Triplets
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level6(List<List<SolverButton>> listid) {
    int diff = 80;
    SudokuButton button = level5(listid);
    int level = 6;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() <= 3) {
          for (int k = j; k < ruut; k++) {
            if (k != j && model.getSudokuButtons()[i][k].getNumber().equals(" ") && model.getSudokuButtons()[i][k].getKandidaate() <= 3) {
              for (int m = k; m < ruut; m++) {
                if (m != k && model.getSudokuButtons()[i][m].getNumber().equals(" ") && model.getSudokuButtons()[i][m].getKandidaate() <= 3) {
                  List<Integer> list = new ArrayList<Integer>();
                  for (int kan = 0; kan < ruut; kan++) {
                    if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                    if (model.getSudokuButtons()[i][k].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                    if (model.getSudokuButtons()[i][m].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                  }
                  if (list.size() <= 3) {
                    boolean b = false;
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = new ArrayList<SolverButton>();
                    for (int l = 0; l < ruut; l++) {
                      if (l != j && l != k && l != m && model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                        for (int kan = 0; kan < list.size(); kan++) {
                          if (model.getSudokuButtons()[i][l].getKandidaat(list.get(kan))) {
                            model.getSudokuButtons()[i][l].removeKandidaat(list.get(kan));
                            list2.add(new SolverButton(i, l, list.get(kan), level));
                            b = true;
                            eemaldatud = true;
                          }
                        }
                      }
                    }
                    if (b) {
                      if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                        List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                        for (int l = 0; l < ruut; l++) {
                          if ((l == j || l == k || l == m) && model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                            list3.add(model.getSudokuButtons()[i][l]);
                          }
                        }
                        if (!removing || solverSeotud.contains(list3)) {
                          levellist.add(list3);
                          levellist2.add(list2);
                          aste.add(new Integer(level));
                        } else {
                          eemaldatud = temp;
                          for (int java = 0; java < list2.size(); java++) {
                            SolverButton butt = list2.get(java);
                            model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                          }
                        }
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                      if (eemaldatud) {
                        return leitud(listid, levellist, levellist2, "Naked triple", level, diff);
                      }
                    }
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaate() <= 3) {
          for (int k = j; k < ruut; k++) {
            if (k != j && model.getSudokuButtons()[k][i].getNumber().equals(" ") && model.getSudokuButtons()[k][i].getKandidaate() <= 3) {
              for (int m = k; m < ruut; m++) {
                if (m != k && model.getSudokuButtons()[m][i].getNumber().equals(" ") && model.getSudokuButtons()[m][i].getKandidaate() <= 3) {
                  List<Integer> list = new ArrayList<Integer>();
                  for (int kan = 0; kan < ruut; kan++) {
                    if (model.getSudokuButtons()[j][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                    if (model.getSudokuButtons()[k][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                    if (model.getSudokuButtons()[m][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                      list.add(new Integer(kan));
                    }
                  }
                  if (list.size() <= 3) {
                    boolean b = false;
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = new ArrayList<SolverButton>();
                    for (int l = 0; l < ruut; l++) {
                      if (l != j && l != k && l != m && model.getSudokuButtons()[l][i].getNumber().equals(" ")) {
                        for (int kan = 0; kan < list.size(); kan++) {
                          if (model.getSudokuButtons()[l][i].getKandidaat(list.get(kan))) {
                            model.getSudokuButtons()[l][i].removeKandidaat(list.get(kan));
                            list2.add(new SolverButton(l, i, list.get(kan), level));
                            b = true;
                            eemaldatud = true;
                          }
                        }
                      }
                    }
                    if (b) {
                      if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                        List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                        for (int l = 0; l < ruut; l++) {
                          if ((l == j || l == k || l == m) && model.getSudokuButtons()[l][i].getNumber().equals(" ")) {
                            list3.add(model.getSudokuButtons()[l][i]);
                          }
                        }
                        if (!removing || solverSeotud.contains(list3)) {
                          levellist.add(list3);
                          levellist2.add(list2);
                          aste.add(new Integer(level));
                        } else {
                          eemaldatud = temp;
                          for (int java = 0; java < list2.size(); java++) {
                            SolverButton butt = list2.get(java);
                            model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                          }
                        }
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                      if (eemaldatud) {
                        return leitud(listid, levellist, levellist2, "Naked triple", level, diff);
                      }
                    }
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() <= 3) {
          int rida1 = 0;
          int veerg1 = 0;
          if (i > (kast - 1) && i < (kast * 2)) {
            rida1 = kast;
          }
          if (i > (kast * 2 - 1) && i < (kast * 3)) {
            rida1 = kast * 2;
          }
          if (i > (kast * 3 - 1) && i < (kast * 4)) {
            rida1 = kast * 3;
          }
          if (j > (kast - 1) && j < (kast * 2)) {
            veerg1 = kast;
          }
          if (j > (kast * 2 - 1) && j < (kast * 3)) {
            veerg1 = kast * 2;
          }
          if (j > (kast * 3 - 1) && j < (kast * 4)) {
            veerg1 = kast * 3;
          }
          for (int k = i; k < (rida1 + kast); k++) {
            for (int l = veerg1; l < (veerg1 + kast); l++) {
              if ((k > i || l > j) && model.getSudokuButtons()[k][l].getNumber().equals(" ")
                  && model.getSudokuButtons()[k][l].getKandidaate() <= 3) {
                for (int o = k; o < (rida1 + kast); o++) {
                  for (int p = veerg1; p < (veerg1 + kast); p++) {
                    if ((o > k || p > l) && model.getSudokuButtons()[o][p].getNumber().equals(" ")
                        && model.getSudokuButtons()[o][p].getKandidaate() <= 3) {
                      List<Integer> list = new ArrayList<Integer>();
                      for (int kan = 0; kan < ruut; kan++) {
                        if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[k][l].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[o][p].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                      }
                      if (list.size() <= 3) {
                        boolean b = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int m = rida1; m < (rida1 + kast); m++) {
                          for (int n = veerg1; n < (veerg1 + kast); n++) {
                            if (!(m == i && n == j) && !(m == k && n == l) && !(m == o && n == p)
                                && model.getSudokuButtons()[m][n].getNumber().equals(" ")) {
                              for (int kan = 0; kan < list.size(); kan++) {
                                if (model.getSudokuButtons()[m][n].getKandidaat(list.get(kan))) {
                                  model.getSudokuButtons()[m][n].removeKandidaat(list.get(kan));
                                  list2.add(new SolverButton(m, n, list.get(kan), level));
                                  b = true;
                                  eemaldatud = true;
                                }
                              }
                            }
                          }
                        }
                        if (b) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int m = i; m < (rida1 + kast); m++) {
                              for (int n = veerg1; n < (veerg1 + kast); n++) {
                                if (((m == i && n == j) || (m == k && n == l) || (m == o && n == p))
                                    && model.getSudokuButtons()[m][n].getNumber().equals(" ")) {
                                  list3.add(model.getSudokuButtons()[m][n]);
                                }
                              }
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Naked triple", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * X-Wing
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level7(List<List<SolverButton>> listid) {
    int diff = 100;
    SudokuButton button = level6(listid);
    int level = 7;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int kan = 0; kan < ruut; kan++) {
      List<List<Integer>> realist = new ArrayList<List<Integer>>();
      List<List<Integer>> veerulist = new ArrayList<List<Integer>>();
      List<List<Integer>> kastilist = new ArrayList<List<Integer>>();
      for (int i = 0; i < ruut; i++) {
        List<Integer> l1 = new ArrayList<Integer>();
        List<Integer> l2 = new ArrayList<Integer>();
        List<Integer> l3 = new ArrayList<Integer>();
        for (int j = 0; j < ruut; j++) {
          if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
            l1.add(new Integer(j));
          }
          if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaat(kan)) {
            l2.add(new Integer(j));
          }
        }
        realist.add(l1);
        veerulist.add(l2);
        int rida = (i / kast) * kast;
        int veerg = (i % kast) * kast;
        for (int k = rida; k < (rida + kast); k++) {
          for (int l = veerg; l < (veerg + kast); l++) {
            if (model.getSudokuButtons()[k][l].getNumber().equals(" ") && model.getSudokuButtons()[k][l].getKandidaat(kan)) {
              l3.add(new Integer(k * 100 + l));
            }
          }
        }
        kastilist.add(l3);
      }
      for (int i = 0; i < ruut; i++) {
        for (int j = i; j < ruut; j++) {
          if (j != i) {
            if ((realist.get(i)).size() > 1 && (realist.get(j)).size() > 1) {
              // realist veerg
              List<Integer> l2 = new ArrayList<Integer>();
              for (int java = 0; java < realist.get(i).size(); java++) {
                Integer a = realist.get(i).get(java);
                if (!l2.contains(a)) {
                  l2.add(a);
                }
              }
              for (int java = 0; java < (realist.get(j)).size(); java++) {
                Integer a = (realist.get(j)).get(java);
                if (!l2.contains(a)) {
                  l2.add(a);
                }
              }
              if (l2.size() == 2) {
                boolean bool = false;
                boolean temp = eemaldatud;
                List<SolverButton> list2 = new ArrayList<SolverButton>();
                for (int l = 0; l < ruut; l++) {
                  for (int java = 0; java < l2.size(); java++) {
                    Integer a = l2.get(java);
                    if (l != i && l != j && model.getSudokuButtons()[l][a.intValue()].getNumber().equals(" ")
                        && model.getSudokuButtons()[l][a.intValue()].getKandidaat(kan)) {
                      model.getSudokuButtons()[l][a.intValue()].removeKandidaat(kan);
                      list2.add(new SolverButton(l, a.intValue(), kan, level));
                      bool = true;
                      eemaldatud = true;
                    }
                  }
                }
                if (bool) {
                  if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                    List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                    for (int java = 0; java < (realist.get(i)).size(); java++) {
                      Integer a = (realist.get(i)).get(java);
                      list3.add(model.getSudokuButtons()[i][a.intValue()]);
                    }
                    for (int java = 0; java < (realist.get(j)).size(); java++) {
                      Integer a = (realist.get(j)).get(java);
                      list3.add(model.getSudokuButtons()[j][a.intValue()]);
                    }
                    if (!removing || solverSeotud.contains(list3)) {
                      levellist.add(list3);
                      levellist2.add(list2);
                      aste.add(new Integer(level));
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                  } else {
                    eemaldatud = temp;
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                  if (eemaldatud) {
                    return leitud(listid, levellist, levellist2, "X-wing", level, diff);
                  }
                }
              }
              // realist kast
              // List<Integer> l3 = new ArrayList<Integer>();
              // for (int java = 0; java < (realist.get(i)).size(); java++) {
              // Integer a = (realist.get(i)).get(java);
              // int koht = ((i / kast) * kast) + (a.intValue() / kast);
              // if (!l3.contains(new Integer(koht))) {
              // l3.add(new Integer(koht));
              // }
              // }
              // for (int java = 0; java < (realist.get(j)).size(); java++) {
              // Integer a = (realist.get(j)).get(java);
              // int koht = ((j / kast) * kast) + (a.intValue() / kast);
              // if (!l3.contains(new Integer(koht))) {
              // l3.add(new Integer(koht));
              // }
              // }
              // if (l3.size() == 2) {
              // boolean bool = false;
              // boolean temp = eemaldatud;
              // List<SolverButton> list2 = new ArrayList<SolverButton>();
              // for (int java = 0; java < l3.size(); java++) {
              // int koht = (l3.get(java)).intValue();
              // int rida = (koht / kast) * kast;
              // int veerg = (koht % kast) * kast;
              // for (int k = rida; k < (rida + kast); k++) {
              // for (int l = veerg; l < (veerg + kast); l++) {
              // if ((k != i || !(realist.get(i)).contains(new Integer(l))) &&
              // (k != j || !(realist.get(j)).contains(new Integer(l))) &&
              // model.getSudokuButtons()[k][l].getNumber().equals(" ") &&
              // model.getSudokuButtons()[k][l].getKandidaat(kan)) {
              // model.getSudokuButtons()[k][l].removeKandidaat(kan);
              // list2.add(new SolverButton(k, l, kan, level));
              // bool = true;
              // eemaldatud = true;
              // }
              // }
              // }
              // }
              // if (bool) {
              // if (!removing || (!listid.contains(list2) &&
              // sammud.contains(list2))) {
              // List<SudokuButton> list3 = new ArrayList<SudokuButton>();
              // for (int java = 0; java < (realist.get(i)).size(); java++) {
              // Integer a = (realist.get(i)).get(java);
              // list3.add(model.getSudokuButtons()[i][a.intValue()]);
              // }
              // for (int java = 0; java < (realist.get(j)).size(); java++) {
              // Integer a = (realist.get(j)).get(java);
              // list3.add(model.getSudokuButtons()[j][a.intValue()]);
              // }
              // if (!removing || solverSeotud.contains(list3)) {
              // levellist.add(list3);
              // levellist2.add(list2);
              // aste.add(new Integer(level));
              // }
              // else {
              // eemaldatud = temp;
              // for (int java = 0; java < list2.size(); java++) {
              // SolverButton butt = list2.get(java);
              // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              // }
              // }
              // }
              // else {
              // eemaldatud = temp;
              // for (int java = 0; java < list2.size(); java++) {
              // SolverButton butt = list2.get(java);
              // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              // }
              // }
              // if (eemaldatud) {
              // return leitud(listid, levellist, levellist2, "X-wing", level,
              // diff);
              // }
              // }
              // }
            }
            if ((veerulist.get(i)).size() > 1 && (veerulist.get(j)).size() > 1) {
              // veerulist rida
              List<Integer> l2 = new ArrayList<Integer>();
              for (int java = 0; java < (veerulist.get(i)).size(); java++) {
                Integer a = (veerulist.get(i)).get(java);
                if (!l2.contains(a)) {
                  l2.add(a);
                }
              }
              for (int java = 0; java < (veerulist.get(j)).size(); java++) {
                Integer a = (veerulist.get(j)).get(java);
                if (!l2.contains(a)) {
                  l2.add(a);
                }
              }
              if (l2.size() == 2) {
                boolean bool = false;
                boolean temp = eemaldatud;
                List<SolverButton> list2 = new ArrayList<SolverButton>();
                for (int l = 0; l < ruut; l++) {
                  for (int java = 0; java < l2.size(); java++) {
                    int a = (l2.get(java)).intValue();
                    if (l != i && l != j && model.getSudokuButtons()[a][l].getNumber().equals(" ")
                        && model.getSudokuButtons()[a][l].getKandidaat(kan)) {
                      model.getSudokuButtons()[a][l].removeKandidaat(kan);
                      list2.add(new SolverButton(a, l, kan, level));
                      bool = true;
                      eemaldatud = true;
                    }
                  }
                }
                if (bool) {
                  if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                    List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                    for (int java = 0; java < (veerulist.get(i)).size(); java++) {
                      Integer a = (veerulist.get(i)).get(java);
                      list3.add(model.getSudokuButtons()[a.intValue()][i]);
                    }
                    for (int java = 0; java < (veerulist.get(j)).size(); java++) {
                      Integer a = (veerulist.get(j)).get(java);
                      list3.add(model.getSudokuButtons()[a.intValue()][j]);
                    }
                    if (!removing || solverSeotud.contains(list3)) {
                      levellist.add(list3);
                      levellist2.add(list2);
                      aste.add(new Integer(level));
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                  } else {
                    eemaldatud = temp;
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                  if (eemaldatud) {
                    return leitud(listid, levellist, levellist2, "X-wing", level, diff);
                  }
                }
              }
              // veerulist kast
              // List<Integer> l3 = new ArrayList<Integer>();
              // for (int java = 0; java < (veerulist.get(i)).size(); java++) {
              // int a = ((veerulist.get(i)).get(java)).intValue();
              // int koht = ((a / kast) * kast) + (i / kast);
              // if (!l3.contains(new Integer(koht))) {
              // l3.add(new Integer(koht));
              // }
              // }
              // for (int java = 0; java < (veerulist.get(j)).size(); java++) {
              // int a = ((veerulist.get(j)).get(java)).intValue();
              // int koht = ((a / kast) * kast) + (j / kast);
              // if (!l3.contains(new Integer(koht))) {
              // l3.add(new Integer(koht));
              // }
              // }
              // if (l3.size() == 2) {
              // boolean bool = false;
              // boolean temp = eemaldatud;
              // List<SolverButton> list2 = new ArrayList<SolverButton>();
              // for (int java = 0; java < (veerulist.get(i)).size(); java++) {
              // int koht = ((veerulist.get(i)).get(java)).intValue();
              // int rida = (koht / kast) * kast;
              // int veerg = (koht % kast) * kast;
              // for (int k = rida; k < (rida + kast); k++) {
              // for (int l = veerg; l < (veerg + kast); l++) {
              // if ((l != i || !(veerulist.get(i)).contains(new Integer(k))) &&
              // (l != j || !(veerulist.get(j)).contains(new Integer(k))) &&
              // model.getSudokuButtons()[k][l].getNumber().equals(" ") &&
              // model.getSudokuButtons()[k][l].getKandidaat(kan)) {
              // model.getSudokuButtons()[k][l].removeKandidaat(kan);
              // list2.add(new SolverButton(k, l, kan, level));
              // bool = true;
              // eemaldatud = true;
              // }
              // }
              // }
              // }
              // if (bool) {
              // if (!removing || (!listid.contains(list2) &&
              // sammud.contains(list2))) {
              // List<SudokuButton> list3 = new ArrayList<SudokuButton>();
              // for (int java = 0; java < (veerulist.get(i)).size(); java++) {
              // Integer a = (veerulist.get(i)).get(java);
              // list3.add(model.getSudokuButtons()[a.intValue()][i]);
              // }
              // for (int java = 0; java < (veerulist.get(j)).size(); java++) {
              // Integer a = (veerulist.get(j)).get(java);
              // list3.add(model.getSudokuButtons()[a.intValue()][j]);
              // }
              // if (!removing || solverSeotud.contains(list3)) {
              // levellist.add(list3);
              // levellist2.add(list2);
              // aste.add(new Integer(level));
              // }
              // else {
              // eemaldatud = temp;
              // for (int java = 0; java < list2.size(); java++) {
              // SolverButton butt = list2.get(java);
              // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              // }
              // }
              // }
              // else {
              // eemaldatud = temp;
              // for (int java = 0; java < list2.size(); java++) {
              // SolverButton butt = list2.get(java);
              // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              // }
              // }
              // if (eemaldatud) {
              // return leitud(listid, levellist, levellist2, "X-wing", level,
              // diff);
              // }
              // }
              // }
            }
            // if ((kastilist.get(i)).size() > 1 && (kastilist.get(j)).size() >
            // 1) {
            // // kastilist rida
            // List<Integer> l2 = new ArrayList<Integer>();
            // for (int java = 0; java < (kastilist.get(i)).size(); java++) {
            // int a = ((kastilist.get(i)).get(java)).intValue();
            // int koht = a / 100;
            // if (!l2.contains(new Integer(koht))) {
            // l2.add(new Integer(koht));
            // }
            // }
            // for (int java = 0; java < (kastilist.get(j)).size(); java++) {
            // int a = ((kastilist.get(j)).get(java)).intValue();
            // int koht = a / 100;
            // if (!l2.contains(new Integer(koht))) {
            // l2.add(new Integer(koht));
            // }
            // }
            // if (l2.size() == 2) {
            // boolean bool = false;
            // boolean temp = eemaldatud;
            // List<SolverButton> list2 = new ArrayList<SolverButton>();
            // for (int l = 0; l < ruut; l++) {
            // for (int java = 0; java < l2.size(); java++) {
            // int a = (l2.get(java)).intValue();
            // if (!(kastilist.get(i)).contains(new Integer(a * 100 + l)) &&
            // !(kastilist.get(j)).contains(new Integer(a * 100 + l)) &&
            // model.getSudokuButtons()[a][l].getNumber().equals(" ") &&
            // model.getSudokuButtons()[a][l].getKandidaat(kan)) {
            // model.getSudokuButtons()[a][l].removeKandidaat(kan);
            // list2.add(new SolverButton(a, l, kan, level));
            // bool = true;
            // eemaldatud = true;
            // }
            // }
            // }
            // if (bool) {
            // if (!removing || (!listid.contains(list2) &&
            // sammud.contains(list2))) {
            // List<SudokuButton> list3 = new ArrayList<SudokuButton>();
            // for (int java = 0; java < (kastilist.get(i)).size(); java++) {
            // int a = ((kastilist.get(i)).get(java)).intValue();
            // list3.add(model.getSudokuButtons()[a / 100][a % 100]);
            // }
            // for (int java = 0; java < (kastilist.get(j)).size(); java++) {
            // int a = ((kastilist.get(j)).get(java)).intValue();
            // list3.add(model.getSudokuButtons()[a / 100][a % 100]);
            // }
            // if (!removing || solverSeotud.contains(list3)) {
            // levellist.add(list3);
            // levellist2.add(list2);
            // aste.add(new Integer(level));
            // }
            // else {
            // eemaldatud = temp;
            // for (int java = 0; java < list2.size(); java++) {
            // SolverButton butt = list2.get(java);
            // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
            // }
            // }
            // }
            // else {
            // eemaldatud = temp;
            // for (int java = 0; java < list2.size(); java++) {
            // SolverButton butt = list2.get(java);
            // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
            // }
            // }
            // if (eemaldatud) {
            // return leitud(listid, levellist, levellist2, "X-wing", level,
            // diff);
            // }
            // }
            // }
            // // kastilist veerg
            // List<Integer> l3 = new ArrayList<Integer>();
            // for (int java = 0; java < (kastilist.get(i)).size(); java++) {
            // int a = ((kastilist.get(i)).get(java)).intValue();
            // int koht = a % 100;
            // if (!l3.contains(new Integer(koht))) {
            // l3.add(new Integer(koht));
            // }
            // }
            // for (int java = 0; java < (kastilist.get(j)).size(); java++) {
            // int a = ((kastilist.get(j)).get(java)).intValue();
            // int koht = a % 100;
            // if (!l3.contains(new Integer(koht))) {
            // l3.add(new Integer(koht));
            // }
            // }
            // if (l3.size() == 2) {
            // boolean bool = false;
            // boolean temp = eemaldatud;
            // List<SolverButton> list2 = new ArrayList<SolverButton>();
            // for (int l = 0; l < ruut; l++) {
            // for (int java = 0; java < l3.size(); java++) {
            // int a = (l3.get(java)).intValue();
            // if (!(kastilist.get(i)).contains(new Integer(l * 100 + a)) &&
            // !(kastilist.get(j)).contains(new Integer(l * 100 + a)) &&
            // model.getSudokuButtons()[l][a].getNumber().equals(" ") &&
            // model.getSudokuButtons()[l][a].getKandidaat(kan)) {
            // model.getSudokuButtons()[l][a].removeKandidaat(kan);
            // list2.add(new SolverButton(l, a, kan, level));
            // bool = true;
            // eemaldatud = true;
            // }
            // }
            // }
            // if (bool) {
            // if (!removing || (!listid.contains(list2) &&
            // sammud.contains(list2))) {
            // List<SudokuButton> list3 = new ArrayList<SudokuButton>();
            // for (int java = 0; java < (kastilist.get(i)).size(); java++) {
            // int a = ((kastilist.get(i)).get(java)).intValue();
            // list3.add(model.getSudokuButtons()[a / 100][a % 100]);
            // }
            // for (int java = 0; java < (kastilist.get(j)).size(); java++) {
            // int a = ((kastilist.get(j)).get(java)).intValue();
            // list3.add(model.getSudokuButtons()[a / 100][a % 100]);
            // }
            // if (!removing || solverSeotud.contains(list3)) {
            // levellist.add(list3);
            // levellist2.add(list2);
            // aste.add(new Integer(level));
            // }
            // else {
            // eemaldatud = temp;
            // for (int java = 0; java < list2.size(); java++) {
            // SolverButton butt = list2.get(java);
            // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
            // }
            // }
            // }
            // else {
            // eemaldatud = temp;
            // for (int java = 0; java < list2.size(); java++) {
            // SolverButton butt = list2.get(java);
            // model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
            // }
            // }
            // if (eemaldatud) {
            // return leitud(listid, levellist, levellist2, "X-wing", level,
            // diff);
            // }
            // }
            // }
            // }
          }
        }
      }
    }
    return null;
  }

  /**
   * Hidden pairs
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level8(List<List<SolverButton>> listid) {
    int diff = 100;
    SudokuButton button = level7(listid);
    int level = 8;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(k)) {
            reas++;
            String s = i + "," + l;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas == 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              int reas2 = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan2)) {
                  reas2++;
                  String s = i + "," + l;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 == 2) {
                if (tempkoht.size() == 2) {
                  boolean bool = false;
                  boolean temp = eemaldatud;
                  List<SolverButton> list2 = new ArrayList<SolverButton>();
                  for (int l = 0; l < ruut; l++) {
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String s = tempkoht.get(java);
                      int a = Integer.parseInt(s.split(",")[0]);
                      int b = Integer.parseInt(s.split(",")[1]);
                      if (l != k && l != kan2 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                          && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                        model.getSudokuButtons()[a][b].removeKandidaat(l);
                        list2.add(new SolverButton(a, b, l, level));
                        bool = true;
                        eemaldatud = true;
                      }
                    }
                  }
                  if (bool) {
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                      for (int java = 0; java < tempkoht.size(); java++) {
                        String s = tempkoht.get(java);
                        int a = Integer.parseInt(s.split(",")[0]);
                        int b = Integer.parseInt(s.split(",")[1]);
                        list3.add(model.getSudokuButtons()[a][b]);
                      }
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Hidden pair", level, diff);
                    }
                  }
                }
              }
            }
          }
        }
      }
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(k)) {
            reas++;
            String s = l + "," + i;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas == 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              int reas2 = 0;
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan2)) {
                  reas2++;
                  String s = l + "," + i;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 == 2) {
                if (tempkoht.size() == 2) {
                  boolean bool = false;
                  boolean temp = eemaldatud;
                  List<SolverButton> list2 = new ArrayList<SolverButton>();
                  for (int l = 0; l < ruut; l++) {
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String s = tempkoht.get(java);
                      int a = Integer.parseInt(s.split(",")[0]);
                      int b = Integer.parseInt(s.split(",")[1]);
                      if (l != k && l != kan2 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                          && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                        model.getSudokuButtons()[a][b].removeKandidaat(l);
                        list2.add(new SolverButton(a, b, l, level));
                        bool = true;
                        eemaldatud = true;
                      }
                    }
                  }
                  if (bool) {
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                      for (int java = 0; java < tempkoht.size(); java++) {
                        String s = tempkoht.get(java);
                        int a = Integer.parseInt(s.split(",")[0]);
                        int b = Integer.parseInt(s.split(",")[1]);
                        list3.add(model.getSudokuButtons()[a][b]);
                      }
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Hidden pair", level, diff);
                    }
                  }
                }
              }
            }
          }
        }
      }
      int rida = (i / kast) * kast;
      int veerg = (i % kast) * kast;
      for (int k = 0; k < ruut; k++) {
        int kastis = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = rida; l < (rida + kast); l++) {
          for (int m = veerg; m < (veerg + kast); m++) {
            if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
              kastis++;
              String s = l + "," + m;
              if (!koht.contains(s)) {
                koht.add(s);
              }
            }
          }
        }
        if (kastis == 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              int kastis2 = 0;
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              for (int l = rida; l < (rida + kast); l++) {
                for (int m = veerg; m < (veerg + kast); m++) {
                  if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan2)) {
                    kastis2++;
                    String s = l + "," + m;
                    if (!tempkoht.contains(s)) {
                      tempkoht.add(s);
                    }
                  }
                }
              }
              if (kastis2 == 2) {
                if (tempkoht.size() == 2) {
                  boolean bool = false;
                  boolean temp = eemaldatud;
                  List<SolverButton> list2 = new ArrayList<SolverButton>();
                  for (int l = 0; l < ruut; l++) {
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String s = tempkoht.get(java);
                      int a = Integer.parseInt(s.split(",")[0]);
                      int b = Integer.parseInt(s.split(",")[1]);
                      if (l != k && l != kan2 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                          && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                        model.getSudokuButtons()[a][b].removeKandidaat(l);
                        list2.add(new SolverButton(a, b, l, level));
                        bool = true;
                        eemaldatud = true;
                      }
                    }
                  }
                  if (bool) {
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                      for (int java = 0; java < tempkoht.size(); java++) {
                        String s = tempkoht.get(java);
                        int a = Integer.parseInt(s.split(",")[0]);
                        int b = Integer.parseInt(s.split(",")[1]);
                        list3.add(model.getSudokuButtons()[a][b]);
                      }
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Hidden pair", level, diff);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * XY-Wing
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level9(List<List<SolverButton>> listid) {
    SudokuButton button = level8(listid);
    if (button != null) {
      return button;
    }
    int diff = 120;
    int level = 9;
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() == 2) {
          List<Integer> ridaveerg = new ArrayList<Integer>();
          List<Integer> ridakast = new ArrayList<Integer>();
          List<Integer> veergkast = new ArrayList<Integer>();
          for (int k = 0; k < ruut; k++) {
            if (model.getSudokuButtons()[i][j].getKandidaat(k)) {
              ridaveerg.add(new Integer(k));
              ridakast.add(new Integer(k));
              veergkast.add(new Integer(k));
            }
          }
          // rida ja veerg
          for (int l = 0; l < ruut; l++) {
            if ((l < (j / kast) * kast || l >= ((j / kast) * kast + kast)) && model.getSudokuButtons()[i][l].getNumber().equals(" ")
                && model.getSudokuButtons()[i][l].getKandidaate() == 2) {
              List<Integer> temp1 = new ArrayList<Integer>();
              for (int java = 0; java < ridaveerg.size(); java++) {
                Integer in = ridaveerg.get(java);
                temp1.add(in);
              }
              for (int k = 0; k < ruut; k++) {
                if (model.getSudokuButtons()[i][l].getKandidaat(k) && !ridaveerg.contains(new Integer(k))) {
                  temp1.add(new Integer(k));
                }
              }
              if (temp1.size() < 4) {
                for (int m = 0; m < ruut; m++) {
                  if (m != i && model.getSudokuButtons()[m][j].getNumber().equals(" ")
                      && model.getSudokuButtons()[m][j].getKandidaate() == 2) {
                    List<Integer> temp2 = new ArrayList<Integer>();
                    for (int java = 0; java < temp1.size(); java++) {
                      Integer in = temp1.get(java);
                      temp2.add(in);
                    }
                    for (int k = 0; k < ruut; k++) {
                      if (model.getSudokuButtons()[m][j].getKandidaat(k) && !temp1.contains(new Integer(k))) {
                        temp2.add(new Integer(k));
                      }
                    }
                    if (temp2.size() == 3) {
                      int x1 = -1;
                      int x2 = -1;
                      int y1 = -1;
                      int y2 = -1;
                      int z1 = -1;
                      int z2 = -1;
                      for (int k = 0; k < ruut; k++) {
                        if (model.getSudokuButtons()[i][j].getKandidaat(k)) {
                          if (x1 == -1) {
                            x1 = k;
                          } else {
                            x2 = k;
                          }
                        }
                        if (model.getSudokuButtons()[i][l].getKandidaat(k)) {
                          if (y1 == -1) {
                            y1 = k;
                          } else {
                            y2 = k;
                          }
                        }
                        if (model.getSudokuButtons()[m][j].getKandidaat(k)) {
                          if (z1 == -1) {
                            z1 = k;
                          } else {
                            z2 = k;
                          }
                        }
                      }
                      int common = -1;
                      if (y1 == z1 && ((x1 == y2 && x2 == z2) || (x2 == y2 && x1 == z2))) {
                        common = y1;
                      } else if (y1 == z2 && ((x1 == y2 && x2 == z1) || (x2 == y2 && x1 == z1))) {
                        common = y1;
                      } else if (y2 == z1 && ((x1 == y1 && x2 == z2) || (x2 == y1 && x1 == z2))) {
                        common = y2;
                      } else if (y2 == z2 && ((x1 == y1 && x2 == z1) || (x2 == y1 && x1 == z1))) {
                        common = y2;
                      }
                      if (common != -1) {
                        List<Point> ydep = xyDependences(i, l, common);
                        List<Point> zdep = xyDependences(m, j, common);
                        boolean b = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int java = 0; java < zdep.size(); java++) {
                          Point point = zdep.get(java);
                          if (ydep.contains(point)) {
                            model.getSudokuButtons()[point.x][point.y].removeKandidaat(common);
                            list2.add(new SolverButton(point.x, point.y, common, level));
                            b = true;
                            eemaldatud = true;
                          }
                        }
                        if (b) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            list3.add(model.getSudokuButtons()[i][j]);
                            list3.add(model.getSudokuButtons()[i][l]);
                            list3.add(model.getSudokuButtons()[m][j]);
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "XY-Wing", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          // rida ja kast
          for (int l = 0; l < ruut; l++) {
            if ((l < (j / kast) * kast || l >= ((j / kast) * kast + kast)) && model.getSudokuButtons()[i][l].getNumber().equals(" ")
                && model.getSudokuButtons()[i][l].getKandidaate() == 2) {
              List<Integer> temp1 = new ArrayList<Integer>();
              for (int java = 0; java < ridakast.size(); java++) {
                Integer in = ridakast.get(java);
                temp1.add(in);
              }
              for (int k = 0; k < ruut; k++) {
                if (model.getSudokuButtons()[i][l].getKandidaat(k) && !ridakast.contains(new Integer(k))) {
                  temp1.add(new Integer(k));
                }
              }
              if (temp1.size() < 4) {
                int rida = (i / kast) * kast;
                int veerg = (j / kast) * kast;
                for (int o = rida; o < (rida + kast); o++) {
                  for (int p = veerg; p < (veerg + kast); p++) {
                    if (o != i && model.getSudokuButtons()[o][p].getNumber().equals(" ")
                        && model.getSudokuButtons()[o][p].getKandidaate() == 2) {
                      List<Integer> temp2 = new ArrayList<Integer>();
                      for (int java = 0; java < temp1.size(); java++) {
                        Integer in = temp1.get(java);
                        temp2.add(in);
                      }
                      for (int k = 0; k < ruut; k++) {
                        if (model.getSudokuButtons()[o][p].getKandidaat(k) && !temp1.contains(new Integer(k))) {
                          temp2.add(new Integer(k));
                        }
                      }
                      if (temp2.size() == 3) {
                        int x1 = -1;
                        int x2 = -1;
                        int y1 = -1;
                        int y2 = -1;
                        int z1 = -1;
                        int z2 = -1;
                        for (int k = 0; k < ruut; k++) {
                          if (model.getSudokuButtons()[i][j].getKandidaat(k)) {
                            if (x1 == -1) {
                              x1 = k;
                            } else {
                              x2 = k;
                            }
                          }
                          if (model.getSudokuButtons()[i][l].getKandidaat(k)) {
                            if (y1 == -1) {
                              y1 = k;
                            } else {
                              y2 = k;
                            }
                          }
                          if (model.getSudokuButtons()[o][p].getKandidaat(k)) {
                            if (z1 == -1) {
                              z1 = k;
                            } else {
                              z2 = k;
                            }
                          }
                        }
                        int common = -1;
                        if (y1 == z1 && ((x1 == y2 && x2 == z2) || (x2 == y2 && x1 == z2))) {
                          common = y1;
                        } else if (y1 == z2 && ((x1 == y2 && x2 == z1) || (x2 == y2 && x1 == z1))) {
                          common = y1;
                        } else if (y2 == z1 && ((x1 == y1 && x2 == z2) || (x2 == y1 && x1 == z2))) {
                          common = y2;
                        } else if (y2 == z2 && ((x1 == y1 && x2 == z1) || (x2 == y1 && x1 == z1))) {
                          common = y2;
                        }
                        if (common != -1) {
                          List<Point> ydep = xyDependences(i, l, common);
                          List<Point> zdep = xyDependences(o, p, common);
                          boolean b = false;
                          boolean temp = eemaldatud;
                          List<SolverButton> list2 = new ArrayList<SolverButton>();
                          for (int java = 0; java < zdep.size(); java++) {
                            Point point = zdep.get(java);
                            if (ydep.contains(point)) {
                              model.getSudokuButtons()[point.x][point.y].removeKandidaat(common);
                              list2.add(new SolverButton(point.x, point.y, common, level));
                              b = true;
                              eemaldatud = true;
                            }
                          }
                          if (b) {
                            if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                              List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                              list3.add(model.getSudokuButtons()[i][j]);
                              list3.add(model.getSudokuButtons()[i][l]);
                              list3.add(model.getSudokuButtons()[o][p]);
                              if (!removing || solverSeotud.contains(list3)) {
                                levellist.add(list3);
                                levellist2.add(list2);
                                aste.add(new Integer(level));
                              } else {
                                eemaldatud = temp;
                                for (int java = 0; java < list2.size(); java++) {
                                  SolverButton butt = list2.get(java);
                                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                }
                              }
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                            if (eemaldatud) {
                              return leitud(listid, levellist, levellist2, "XY-Wing", level, diff);
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
          // veerg ja kast
          for (int l = 0; l < ruut; l++) {
            if ((l < (i / kast) * kast || l >= ((i / kast) * kast + kast)) && model.getSudokuButtons()[l][j].getNumber().equals(" ")
                && model.getSudokuButtons()[l][j].getKandidaate() == 2) {
              List<Integer> temp1 = new ArrayList<Integer>();
              for (int java = 0; java < veergkast.size(); java++) {
                Integer in = veergkast.get(java);
                temp1.add(in);
              }
              for (int k = 0; k < ruut; k++) {
                if (model.getSudokuButtons()[l][j].getKandidaat(k) && !veergkast.contains(new Integer(k))) {
                  temp1.add(new Integer(k));
                }
              }
              if (temp1.size() < 4) {
                int rida = (i / kast) * kast;
                int veerg = (j / kast) * kast;
                for (int o = rida; o < (rida + kast); o++) {
                  for (int p = veerg; p < (veerg + kast); p++) {
                    if (p != j && model.getSudokuButtons()[o][p].getNumber().equals(" ")
                        && model.getSudokuButtons()[o][p].getKandidaate() == 2) {
                      List<Integer> temp2 = new ArrayList<Integer>();
                      for (int java = 0; java < temp1.size(); java++) {
                        Integer in = temp1.get(java);
                        temp2.add(in);
                      }
                      for (int k = 0; k < ruut; k++) {
                        if (model.getSudokuButtons()[o][p].getKandidaat(k) && !temp1.contains(new Integer(k))) {
                          temp2.add(new Integer(k));
                        }
                      }
                      if (temp2.size() == 3) {
                        int x1 = -1;
                        int x2 = -1;
                        int y1 = -1;
                        int y2 = -1;
                        int z1 = -1;
                        int z2 = -1;
                        for (int k = 0; k < ruut; k++) {
                          if (model.getSudokuButtons()[i][j].getKandidaat(k)) {
                            if (x1 == -1) {
                              x1 = k;
                            } else {
                              x2 = k;
                            }
                          }
                          if (model.getSudokuButtons()[l][j].getKandidaat(k)) {
                            if (y1 == -1) {
                              y1 = k;
                            } else {
                              y2 = k;
                            }
                          }
                          if (model.getSudokuButtons()[o][p].getKandidaat(k)) {
                            if (z1 == -1) {
                              z1 = k;
                            } else {
                              z2 = k;
                            }
                          }
                        }
                        int common = -1;
                        if (y1 == z1 && ((x1 == y2 && x2 == z2) || (x2 == y2 && x1 == z2))) {
                          common = y1;
                        } else if (y1 == z2 && ((x1 == y2 && x2 == z1) || (x2 == y2 && x1 == z1))) {
                          common = y1;
                        } else if (y2 == z1 && ((x1 == y1 && x2 == z2) || (x2 == y1 && x1 == z2))) {
                          common = y2;
                        } else if (y2 == z2 && ((x1 == y1 && x2 == z1) || (x2 == y1 && x1 == z1))) {
                          common = y2;
                        }
                        if (common != -1) {
                          List<Point> ydep = xyDependences(l, j, common);
                          List<Point> zdep = xyDependences(o, p, common);
                          boolean b = false;
                          boolean temp = eemaldatud;
                          List<SolverButton> list2 = new ArrayList<SolverButton>();
                          for (int java = 0; java < zdep.size(); java++) {
                            Point point = zdep.get(java);
                            if (ydep.contains(point)) {
                              model.getSudokuButtons()[point.x][point.y].removeKandidaat(common);
                              list2.add(new SolverButton(point.x, point.y, common, level));
                              b = true;
                              eemaldatud = true;
                            }
                          }
                          if (b) {
                            if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                              List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                              list3.add(model.getSudokuButtons()[i][j]);
                              list3.add(model.getSudokuButtons()[l][j]);
                              list3.add(model.getSudokuButtons()[o][p]);
                              if (!removing || solverSeotud.contains(list3)) {
                                levellist.add(list3);
                                levellist2.add(list2);
                                aste.add(new Integer(level));
                              } else {
                                eemaldatud = temp;
                                for (int java = 0; java < list2.size(); java++) {
                                  SolverButton butt = list2.get(java);
                                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                }
                              }
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                            if (eemaldatud) {
                              return leitud(listid, levellist, levellist2, "XY-Wing", level, diff);
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Naked Quads
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level10(List<List<SolverButton>> listid) {
    int diff = 130;
    SudokuButton button = level9(listid);
    int level = 10;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() <= 4) {
          for (int k = j; k < ruut; k++) {
            if (k != j && model.getSudokuButtons()[i][k].getNumber().equals(" ") && model.getSudokuButtons()[i][k].getKandidaate() <= 4) {
              for (int m = k; m < ruut; m++) {
                if (m != k && model.getSudokuButtons()[i][m].getNumber().equals(" ") && model.getSudokuButtons()[i][m].getKandidaate() <= 4) {
                  for (int n = m; n < ruut; n++) {
                    if (n != m && model.getSudokuButtons()[i][n].getNumber().equals(" ")
                        && model.getSudokuButtons()[i][n].getKandidaate() <= 4) {
                      List<Integer> list = new ArrayList<Integer>();
                      for (int kan = 0; kan < ruut; kan++) {
                        if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[i][k].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[i][m].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[i][n].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                      }
                      if (list.size() <= 4) {
                        boolean b = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          if (l != j && l != k && l != m && l != n && model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                            for (int kan = 0; kan < list.size(); kan++) {
                              if (model.getSudokuButtons()[i][l].getKandidaat(list.get(kan))) {
                                model.getSudokuButtons()[i][l].removeKandidaat(list.get(kan));
                                list2.add(new SolverButton(i, l, list.get(kan), level));
                                b = true;
                                eemaldatud = true;
                              }
                            }
                          }
                        }
                        if (b) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int l = 0; l < ruut; l++) {
                              if ((l == j || l == k || l == m || l == n) && model.getSudokuButtons()[i][l].getNumber().equals(" ")) {
                                list3.add(model.getSudokuButtons()[i][l]);
                              }
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Naked quad", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaate() <= 4) {
          for (int k = j; k < ruut; k++) {
            if (k != j && model.getSudokuButtons()[k][i].getNumber().equals(" ") && model.getSudokuButtons()[k][i].getKandidaate() <= 4) {
              for (int m = k; m < ruut; m++) {
                if (m != k && model.getSudokuButtons()[m][i].getNumber().equals(" ") && model.getSudokuButtons()[m][i].getKandidaate() <= 4) {
                  for (int n = m; n < ruut; n++) {
                    if (n != m && model.getSudokuButtons()[n][i].getNumber().equals(" ")
                        && model.getSudokuButtons()[n][i].getKandidaate() <= 4) {
                      List<Integer> list = new ArrayList<Integer>();
                      for (int kan = 0; kan < ruut; kan++) {
                        if (model.getSudokuButtons()[j][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[k][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[m][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                        if (model.getSudokuButtons()[n][i].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                          list.add(new Integer(kan));
                        }
                      }
                      if (list.size() <= 4) {
                        boolean b = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          if (l != j && l != k && l != m && l != n && model.getSudokuButtons()[l][i].getNumber().equals(" ")) {
                            for (int kan = 0; kan < list.size(); kan++) {
                              if (model.getSudokuButtons()[l][i].getKandidaat(list.get(kan))) {
                                model.getSudokuButtons()[l][i].removeKandidaat(list.get(kan));
                                list2.add(new SolverButton(l, i, list.get(kan), level));
                                b = true;
                                eemaldatud = true;
                              }
                            }
                          }
                        }
                        if (b) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int l = 0; l < ruut; l++) {
                              if ((l == j || l == k || l == m || l == n) && model.getSudokuButtons()[l][i].getNumber().equals(" ")) {
                                list3.add(model.getSudokuButtons()[l][i]);
                              }
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Naked quad", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaate() <= 4) {
          int rida1 = 0;
          int veerg1 = 0;
          if (i > (kast - 1) && i < (kast * 2)) {
            rida1 = kast;
          }
          if (i > (kast * 2 - 1) && i < (kast * 3)) {
            rida1 = kast * 2;
          }
          if (i > (kast * 3 - 1) && i < (kast * 4)) {
            rida1 = kast * 3;
          }
          if (j > (kast - 1) && j < (kast * 2)) {
            veerg1 = kast;
          }
          if (j > (kast * 2 - 1) && j < (kast * 3)) {
            veerg1 = kast * 2;
          }
          if (j > (kast * 3 - 1) && j < (kast * 4)) {
            veerg1 = kast * 3;
          }
          for (int k = i; k < (rida1 + kast); k++) {
            for (int l = veerg1; l < (veerg1 + kast); l++) {
              if ((k > i || l > j) && model.getSudokuButtons()[k][l].getNumber().equals(" ")
                  && model.getSudokuButtons()[k][l].getKandidaate() <= 4) {
                for (int o = k; o < (rida1 + kast); o++) {
                  for (int p = veerg1; p < (veerg1 + kast); p++) {
                    if ((o > k || p > l) && model.getSudokuButtons()[o][p].getNumber().equals(" ")
                        && model.getSudokuButtons()[o][p].getKandidaate() <= 4) {
                      for (int q = o; q < (rida1 + kast); q++) {
                        for (int r = veerg1; r < (veerg1 + kast); r++) {
                          if ((q > o || r > p) && model.getSudokuButtons()[q][r].getNumber().equals(" ")
                              && model.getSudokuButtons()[q][r].getKandidaate() <= 4) {
                            List<Integer> list = new ArrayList<Integer>();
                            for (int kan = 0; kan < ruut; kan++) {
                              if (model.getSudokuButtons()[i][j].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                                list.add(new Integer(kan));
                              }
                              if (model.getSudokuButtons()[k][l].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                                list.add(new Integer(kan));
                              }
                              if (model.getSudokuButtons()[o][p].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                                list.add(new Integer(kan));
                              }
                              if (model.getSudokuButtons()[q][r].getKandidaat(kan) && !list.contains(new Integer(kan))) {
                                list.add(new Integer(kan));
                              }
                            }
                            if (list.size() <= 4) {
                              boolean b = false;
                              boolean temp = eemaldatud;
                              List<SolverButton> list2 = new ArrayList<SolverButton>();
                              for (int m = i; m < (rida1 + kast); m++) {
                                for (int n = veerg1; n < (veerg1 + kast); n++) {
                                  if (!(m == i && n == j) && !(m == k && n == l) && !(m == o && n == p) && !(m == q && n == r)
                                      && model.getSudokuButtons()[m][n].getNumber().equals(" ")) {
                                    for (int kan = 0; kan < list.size(); kan++) {
                                      if (model.getSudokuButtons()[m][n].getKandidaat(list.get(kan))) {
                                        model.getSudokuButtons()[m][n].removeKandidaat(list.get(kan));
                                        list2.add(new SolverButton(m, n, list.get(kan), level));
                                        b = true;
                                        eemaldatud = true;
                                      }
                                    }
                                  }
                                }
                              }
                              if (b) {
                                if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                                  for (int m = i; m < (rida1 + kast); m++) {
                                    for (int n = veerg1; n < (veerg1 + kast); n++) {
                                      if (((m == i && n == j) || (m == k && n == l) || (m == o && n == p) || (m == q && n == r))
                                          && model.getSudokuButtons()[m][n].getNumber().equals(" ")) {
                                        list3.add(model.getSudokuButtons()[m][n]);
                                      }
                                    }
                                  }
                                  if (!removing || solverSeotud.contains(list3)) {
                                    levellist.add(list3);
                                    levellist2.add(list2);
                                    aste.add(new Integer(level));
                                  } else {
                                    eemaldatud = temp;
                                    for (int java = 0; java < list2.size(); java++) {
                                      SolverButton butt = list2.get(java);
                                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                    }
                                  }
                                } else {
                                  eemaldatud = temp;
                                  for (int java = 0; java < list2.size(); java++) {
                                    SolverButton butt = list2.get(java);
                                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                  }
                                }
                                if (eemaldatud) {
                                  return leitud(listid, levellist, levellist2, "Naked quad", level, diff);
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Colors
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level12(List<List<SolverButton>> listid) {
    int diff = 150;
    SudokuButton button = level11(listid);
    int level = 12;
    if (button != null) {
      return button;
    }
    resetAllColors();
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    multiColorKandidaadid = new ArrayList<Integer>();
    for (int k = 0; k < ruut; k++) {
      int col = 1;
      for (int i = 0; i < ruut; i++) {
        int rida = (i / kast) * kast;
        int veerg = (i % kast) * kast;
        boolean leiti = false;
        int reas = 0;
        int reascol = 0;
        int teinei = 0;
        int teinej = 0;
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(k)) {
            reas++;
            if (model.getSudokuButtons()[i][l].getColor(k) == -1) {
              reascol++;
              teinei = i;
              teinej = l;
            }
          }
        }
        if (reas == 2 && reascol == 2) {
          if (col > 2 && !multiColorKandidaadid.contains(new Integer(k))) {
            multiColorKandidaadid.add(new Integer(k));
          }
          setColors(teinei, teinej, k, col);
          col += 2;
          leiti = true;
        }
        int veerus = 0;
        int veeruscol = 0;
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(k)) {
            veerus++;
            if (model.getSudokuButtons()[l][i].getColor(k) == -1) {
              veeruscol++;
              teinei = l;
              teinej = i;
            }
          }
        }
        if (veerus == 2 && veeruscol == 2) {
          if (col > 2 && !multiColorKandidaadid.contains(new Integer(k))) {
            multiColorKandidaadid.add(new Integer(k));
          }
          setColors(teinei, teinej, k, col);
          col += 2;
          leiti = true;
        }
        int kastis = 0;
        int kastiscol = 0;
        for (int l = rida; l < (rida + kast); l++) {
          for (int m = veerg; m < (veerg + kast); m++) {
            if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
              kastis++;
              if (model.getSudokuButtons()[l][m].getColor(k) == -1) {
                kastiscol++;
                teinei = l;
                teinej = m;
              }
            }
          }
        }
        if (kastis == 2 && kastiscol == 2) {
          if (col > 2 && !multiColorKandidaadid.contains(new Integer(k))) {
            multiColorKandidaadid.add(new Integer(k));
          }
          setColors(teinei, teinej, k, col);
          col += 2;
          leiti = true;
        }
        if (leiti) {
          for (int l = 0; l < ruut; l++) {
            for (int m = 0; m < ruut; m++) {
              if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)
                  && model.getSudokuButtons()[l][m].getColor(k) == -1) {
                List<Integer> list = getDependentColors(l, m, k);
                List<Integer> listtemp = new ArrayList<Integer>();
                for (int java = 0; java < list.size(); java++) {
                  Integer nu = list.get(java);
                  if (!listtemp.contains(nu)) {
                    listtemp.add(nu);
                  }
                }
                Collections.sort(listtemp);
                for (int j = 1; j < listtemp.size(); j++) {
                  int nr1 = (listtemp.get(j - 1)).intValue();
                  int nr2 = (listtemp.get(j)).intValue();
                  if (nr2 - nr1 == 1 && nr2 % 2 == 0) {
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = new ArrayList<SolverButton>();
                    model.getSudokuButtons()[l][m].removeKandidaat(k);
                    list2.add(new SolverButton(l, m, k, level));
                    eemaldatud = true;
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      List<SudokuButton> list3 = getColorButtons(k, nr1);
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Colors", level, diff);
                    }
                  }
                }
              }
              if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)
                  && model.getSudokuButtons()[l][m].getColor(k) != -1) {
                List<Integer> list = getDependentColors(l, m, k);
                int palju = 0;
                for (int java = 0; java < list.size(); java++) {
                  Integer nu = list.get(java);
                  if (nu.intValue() == model.getSudokuButtons()[l][m].getColor(k)) {
                    palju++;
                  }
                }
                if (palju > 3) {
                  boolean temp = eemaldatud;
                  List<SolverButton> list2 = getColorRemoveButtons(k, model.getSudokuButtons()[l][m].getColor(k), level);

                  for (int java = 0; java < list2.size(); java++) {
                    SolverButton butt = list2.get(java);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
                  }
                  eemaldatud = true;
                  if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                    int tempcol = model.getSudokuButtons()[l][m].getColor(k);
                    if (tempcol % 2 == 0) {
                      tempcol--;
                    }
                    List<SudokuButton> list3 = getColorButtons(k, tempcol);
                    if (!removing || solverSeotud.contains(list3)) {
                      levellist.add(list3);
                      levellist2.add(list2);
                      aste.add(new Integer(level));
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                  } else {
                    eemaldatud = temp;
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                    }
                  }
                  if (eemaldatud) {
                    return leitud(listid, levellist, levellist2, "Colors", level, diff);
                  }
                }
              }
            }
          }
          for (int j = 0; j < ruut; j++) {
            int siserida = (j / kast) * kast;
            int siseveerg = (j % kast) * kast;
            List<Integer> list = new ArrayList<Integer>();
            int arv = 0;
            boolean vaja = true;
            for (int l = 0; l < ruut; l++) {
              if (model.getSudokuButtons()[j][l].getNumber().equals(" ") && model.getSudokuButtons()[j][l].getKandidaat(k)) {
                if (model.getSudokuButtons()[j][l].getColor(k) != -1) {
                  vaja = false;
                  break;
                }
                List<Integer> t = getDependentColBoxColors(j, l, k);
                if (t.size() == 0) {
                  vaja = false;
                  break;
                }
                List<Integer> ttemp = new ArrayList<Integer>();
                for (int java = 0; java < t.size(); java++) {
                  Integer nu = t.get(java);
                  if (!ttemp.contains(nu)) {
                    ttemp.add(nu);
                  }
                }
                Collections.sort(ttemp);
                for (int o = 1; o < ttemp.size(); o++) {
                  int nr1 = (ttemp.get(o - 1)).intValue();
                  int nr2 = (ttemp.get(o)).intValue();
                  if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                    list.add(new Integer(nr1));
                  }
                }
                arv++;
              }
            }
            if (vaja) {
              List<Integer> ttemp = new ArrayList<Integer>();
              for (int java = 0; java < list.size(); java++) {
                Integer nu = list.get(java);
                if (!ttemp.contains(nu)) {
                  ttemp.add(nu);
                }
              }
              Collections.sort(ttemp);
              for (int o = 1; o < ttemp.size(); o++) {
                int nr1 = (ttemp.get(o - 1)).intValue();
                int nr2 = (ttemp.get(o)).intValue();
                if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                  int palju = 0;
                  for (int java = 0; java < list.size(); java++) {
                    Integer nu = list.get(java);
                    if (nu.intValue() == nr1) {
                      palju++;
                    }
                  }
                  if (palju == arv) {
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = getColorRemoveButtons(k, nr1, level);
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
                    }
                    eemaldatud = true;
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      int tempcol = nr1;
                      if (tempcol % 2 == 0) {
                        tempcol--;
                      }
                      List<SudokuButton> list3 = getColorButtons(k, tempcol);
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Colors", level, diff);
                    }
                  }
                }
              }
            }
            list = new ArrayList<Integer>();
            arv = 0;
            vaja = true;
            for (int l = 0; l < ruut; l++) {
              if (model.getSudokuButtons()[l][j].getNumber().equals(" ") && model.getSudokuButtons()[l][j].getKandidaat(k)) {
                if (model.getSudokuButtons()[l][j].getColor(k) != -1) {
                  vaja = false;
                  break;
                }
                List<Integer> t = getDependentRowBoxColors(l, j, k);
                if (t.size() == 0) {
                  vaja = false;
                  break;
                }
                List<Integer> ttemp = new ArrayList<Integer>();
                for (int java = 0; java < t.size(); java++) {
                  Integer nu = t.get(java);
                  if (!ttemp.contains(nu)) {
                    ttemp.add(nu);
                  }
                }
                Collections.sort(ttemp);
                for (int o = 1; o < ttemp.size(); o++) {
                  int nr1 = (ttemp.get(o - 1)).intValue();
                  int nr2 = (ttemp.get(o)).intValue();
                  if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                    list.add(new Integer(nr1));
                  }
                }
                arv++;
              }
            }
            if (vaja) {
              List<Integer> ttemp = new ArrayList<Integer>();
              for (int java = 0; java < list.size(); java++) {
                Integer nu = list.get(java);
                if (!ttemp.contains(nu)) {
                  ttemp.add(nu);
                }
              }
              Collections.sort(ttemp);
              for (int o = 1; o < ttemp.size(); o++) {
                int nr1 = (ttemp.get(o - 1)).intValue();
                int nr2 = (ttemp.get(o)).intValue();
                if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                  int palju = 0;
                  for (int java = 0; java < list.size(); java++) {
                    Integer nu = list.get(java);
                    if (nu.intValue() == nr1) {
                      palju++;
                    }
                  }
                  if (palju == arv) {
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = getColorRemoveButtons(k, nr1, level);
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
                    }
                    eemaldatud = true;
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      int tempcol = nr1;
                      if (tempcol % 2 == 0) {
                        tempcol--;
                      }
                      List<SudokuButton> list3 = getColorButtons(k, tempcol);
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Colors", level, diff);
                    }
                  }
                }
              }
            }
            list = new ArrayList<Integer>();
            arv = 0;
            vaja = true;
            for (int l = siserida; l < (siserida + kast); l++) {
              for (int m = siseveerg; m < (siseveerg + kast); m++) {
                if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
                  if (model.getSudokuButtons()[l][m].getColor(k) != -1) {
                    vaja = false;
                    break;
                  }
                  List<Integer> t = getDependentRowColColors(l, m, k);
                  if (t.size() == 0) {
                    vaja = false;
                    break;
                  }
                  List<Integer> ttemp = new ArrayList<Integer>();
                  for (int java = 0; java < t.size(); java++) {
                    Integer nu = t.get(java);
                    if (!ttemp.contains(nu)) {
                      ttemp.add(nu);
                    }
                  }
                  Collections.sort(ttemp);
                  for (int o = 1; o < ttemp.size(); o++) {
                    int nr1 = (ttemp.get(o - 1)).intValue();
                    int nr2 = (ttemp.get(o)).intValue();
                    if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                      list.add(new Integer(nr1));
                    }
                  }
                  arv++;
                }
              }
            }
            if (vaja) {
              List<Integer> ttemp = new ArrayList<Integer>();
              for (int java = 0; java < list.size(); java++) {
                Integer nu = list.get(java);
                if (!ttemp.contains(nu)) {
                  ttemp.add(nu);
                }
              }
              Collections.sort(ttemp);
              for (int o = 1; o < ttemp.size(); o++) {
                int nr1 = (ttemp.get(o - 1)).intValue();
                int nr2 = (ttemp.get(o)).intValue();
                if (nr2 - nr1 != 1 || nr2 % 2 != 0) {
                  int palju = 0;
                  for (int java = 0; java < list.size(); java++) {
                    Integer nu = list.get(java);
                    if (nu.intValue() == nr1) {
                      palju++;
                    }
                  }
                  if (palju == arv) {
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = getColorRemoveButtons(k, nr1, level);
                    for (int java = 0; java < list2.size(); java++) {
                      SolverButton butt = list2.get(java);
                      model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
                    }
                    eemaldatud = true;
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      int tempcol = nr1;
                      if (tempcol % 2 == 0) {
                        tempcol--;
                      }
                      List<SudokuButton> list3 = getColorButtons(k, tempcol);
                      if (!removing || solverSeotud.contains(list3)) {
                        levellist.add(list3);
                        levellist2.add(list2);
                        aste.add(new Integer(level));
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                    } else {
                      eemaldatud = temp;
                      for (int java = 0; java < list2.size(); java++) {
                        SolverButton butt = list2.get(java);
                        model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                      }
                    }
                    if (eemaldatud) {
                      return leitud(listid, levellist, levellist2, "Colors", level, diff);
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Swordfish
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level11(List<List<SolverButton>> listid) {
    int diff = 190;
    SudokuButton button = level10(listid);
    int level = 11;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int kan = 0; kan < ruut; kan++) {
      List<List<Integer>> realist = new ArrayList<List<Integer>>();
      List<List<Integer>> veerulist = new ArrayList<List<Integer>>();
      for (int i = 0; i < ruut; i++) {
        List<Integer> l1 = new ArrayList<Integer>();
        List<Integer> l2 = new ArrayList<Integer>();
        for (int j = 0; j < ruut; j++) {
          if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
            l1.add(new Integer(j));
          }
          if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaat(kan)) {
            l2.add(new Integer(j));
          }
        }
        realist.add(l1);
        veerulist.add(l2);
      }
      for (int i = 0; i < ruut; i++) {
        for (int j = i; j < ruut; j++) {
          if (j != i) {
            for (int k = j; k < ruut; k++) {
              if (k != j) {
                List<Integer> rl1 = realist.get(i);
                List<Integer> rl2 = realist.get(j);
                List<Integer> rl3 = realist.get(k);
                Set<Integer> set = new HashSet<Integer>();
                set.addAll(rl1);
                set.addAll(rl2);
                set.addAll(rl3);
                if ((rl1).size() > 1 && (rl2).size() > 1 && (rl3).size() > 1 && set.size() == 3) {
                  // realist veerg
                  List<Integer> l2 = new ArrayList<Integer>();
                  for (int java = 0; java < rl1.size(); java++) {
                    Integer a = rl1.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  for (int java = 0; java < rl2.size(); java++) {
                    Integer a = rl2.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  for (int java = 0; java < rl3.size(); java++) {
                    Integer a = rl3.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  if (l2.size() == 3) {
                    boolean bool = false;
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = new ArrayList<SolverButton>();
                    for (int l = 0; l < ruut; l++) {
                      for (int java = 0; java < l2.size(); java++) {
                        Integer a = l2.get(java);
                        if (l != i && l != j && l != k && model.getSudokuButtons()[l][a.intValue()].getNumber().equals(" ")
                            && model.getSudokuButtons()[l][a.intValue()].getKandidaat(kan)) {
                          model.getSudokuButtons()[l][a.intValue()].removeKandidaat(kan);
                          list2.add(new SolverButton(l, a, kan, level));
                          bool = true;
                          eemaldatud = true;
                        }
                      }
                    }
                    if (bool) {
                      if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                        List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                        for (int java = 0; java < rl1.size(); java++) {
                          Integer a = rl1.get(java);
                          list3.add(model.getSudokuButtons()[i][a.intValue()]);
                        }
                        for (int java = 0; java < rl2.size(); java++) {
                          Integer a = rl2.get(java);
                          list3.add(model.getSudokuButtons()[j][a.intValue()]);
                        }
                        for (int java = 0; java < rl3.size(); java++) {
                          Integer a = rl3.get(java);
                          list3.add(model.getSudokuButtons()[k][a.intValue()]);
                        }
                        if (!removing || solverSeotud.contains(list3)) {
                          levellist.add(list3);
                          levellist2.add(list2);
                          aste.add(new Integer(level));
                        } else {
                          eemaldatud = temp;
                          for (int java = 0; java < list2.size(); java++) {
                            SolverButton butt = list2.get(java);
                            model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                          }
                        }
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                      if (eemaldatud) {
                        return leitud(listid, levellist, levellist2, "Swordfish", level, diff);
                      }
                    }
                  }
                }
                List<Integer> vl1 = veerulist.get(i);
                List<Integer> vl2 = veerulist.get(j);
                List<Integer> vl3 = veerulist.get(k);
                set = new HashSet<Integer>();
                set.addAll(vl1);
                set.addAll(vl2);
                set.addAll(vl3);
                if ((vl1).size() > 1 && (vl2).size() > 1 && (vl3).size() > 1 && set.size() == 3) {
                  // veerulist rida
                  List<Integer> l2 = new ArrayList<Integer>();
                  for (int java = 0; java < vl1.size(); java++) {
                    Integer a = vl1.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  for (int java = 0; java < vl2.size(); java++) {
                    Integer a = vl2.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  for (int java = 0; java < vl3.size(); java++) {
                    Integer a = vl3.get(java);
                    if (!l2.contains(a)) {
                      l2.add(a);
                    }
                  }
                  if (l2.size() == 3) {
                    boolean bool = false;
                    boolean temp = eemaldatud;
                    List<SolverButton> list2 = new ArrayList<SolverButton>();
                    for (int l = 0; l < ruut; l++) {
                      for (int java = 0; java < l2.size(); java++) {
                        Integer a = l2.get(java);
                        if (l != i && l != j && l != k && model.getSudokuButtons()[a.intValue()][l].getNumber().equals(" ")
                            && model.getSudokuButtons()[a.intValue()][l].getKandidaat(kan)) {
                          model.getSudokuButtons()[a.intValue()][l].removeKandidaat(kan);
                          list2.add(new SolverButton(a, l, kan, level));
                          bool = true;
                          eemaldatud = true;
                        }
                      }
                    }
                    if (bool) {
                      if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                        List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                        for (int java = 0; java < vl1.size(); java++) {
                          Integer a = vl1.get(java);
                          list3.add(model.getSudokuButtons()[a.intValue()][i]);
                        }
                        for (int java = 0; java < vl2.size(); java++) {
                          Integer a = vl2.get(java);
                          list3.add(model.getSudokuButtons()[a.intValue()][j]);
                        }
                        for (int java = 0; java < vl3.size(); java++) {
                          Integer a = vl3.get(java);
                          list3.add(model.getSudokuButtons()[a.intValue()][k]);
                        }
                        if (!removing || solverSeotud.contains(list3)) {
                          levellist.add(list3);
                          levellist2.add(list2);
                          aste.add(new Integer(level));
                        } else {
                          eemaldatud = temp;
                          for (int java = 0; java < list2.size(); java++) {
                            SolverButton butt = list2.get(java);
                            model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                          }
                        }
                      } else {
                        eemaldatud = temp;
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                        }
                      }
                      if (eemaldatud) {
                        return leitud(listid, levellist, levellist2, "Swordfish", level, diff);
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Forcing Chains
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level17(List<List<SolverButton>> listid) {
    SudokuButton button = level16(listid);
    if (button != null) {
      return button;
    }
    int diff = 450;
    int level = 17;
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    ForceChainButton[][] chain = createChain();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (chain[i][j] != null && chain[i][j].getKandidaadid().size() == 2) {
          chain[i][j].getKandidaadid().get(0).setForceDown(1);
          chain[i][j].getKandidaadid().get(1).setForceUp(1);
          List<FilterCandidate> empty = Collections.emptyList();
          followChain(chain, i, j, 0, 0, empty);

          boolean bool = false;
          boolean temp = eemaldatud;
          List<SolverButton> list2 = new ArrayList<SolverButton>();
          for (int k = 0; k < ruut; k++) {
            for (int l = 0; l < ruut; l++) {
              if (chain[k][l] != null) {
                for (Candidate c : chain[k][l].getKandidaadid()) {
                  if (c.isForceDown() && c.isForceUp()) {
                    list2.add(new SolverButton(k, l, c.getKandidaat(), level));
                    if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                      minimizeChain(i, j, chain, list2.get(0));
                      model.getSudokuButtons()[k][l].removeKandidaat(c.getKandidaat());
                      bool = true;
                      eemaldatud = true;
                      break;
                    } else {
                      list2.clear();
                    }
                  }
                }
              }
              if (bool) {
                break;
              }
            }
            if (bool) {
              break;
            }
          }
          if (bool) {
            if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
              List<SudokuButton> list3 = new ArrayList<SudokuButton>();
              for (int k = 0; k < ruut; k++) {
                for (int l = 0; l < ruut; l++) {
                  if (chain[k][l] != null) {
                    for (Candidate c : chain[k][l].getKandidaadid()) {
                      if (c.isForceDown() || c.isForceUp()) {
                        list3.add(model.getSudokuButtons()[k][l]);
                      }
                    }
                  }
                }
              }
              if (!removing || solverSeotud.contains(list3)) {
                levellist.add(list3);
                levellist2.add(list2);
                aste.add(new Integer(level));
              } else {
                eemaldatud = temp;
                for (int java = 0; java < list2.size(); java++) {
                  SolverButton butt = list2.get(java);
                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                }
              }
            } else {
              eemaldatud = temp;
              for (int java = 0; java < list2.size(); java++) {
                SolverButton butt = list2.get(java);
                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
              }
            }
            if (eemaldatud) {
              return leitud(listid, levellist, levellist2, "Forcing Chains", level, diff);
            }
          }
          for (int k = 0; k < ruut; k++) {
            for (int l = 0; l < ruut; l++) {
              if (chain[k][l] != null) {
                chain[k][l].resetKandidaadid();
              }
            }
          }
        }
      }
    }

    return null;
  }

  private ForceChainButton[][] createChain() {
    ForceChainButton[][] chain = new ForceChainButton[ruut][ruut];
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
          chain[i][j] = new ForceChainButton(i, j, model.getSudokuButtons()[i][j].getKandidaadid());
        }
      }
    }
    return chain;
  }

  private void minimizeChain(int startI, int startJ, ForceChainButton[][] chain, SolverButton button) {
    List<FilterCandidate> filter = new ArrayList<FilterCandidate>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (chain[i][j] != null && !(i == button.getI() && j == button.getJ()) && !(i == startI && j == startJ)) {
          for (Candidate c : chain[i][j].getKandidaadid()) {
            if (c.isForceUp() || c.isForceDown()) {
              ForceChainButton[][] tmp = createChain();
              tmp[startI][startJ].getKandidaadid().get(0).setForceDown(1);
              tmp[startI][startJ].getKandidaadid().get(1).setForceUp(1);

              FilterCandidate fc = new FilterCandidate(i, j, c.getKandidaat());
              filter.add(fc);

              followChain(tmp, startI, startJ, 0, 0, filter);
              Candidate tmpC = tmp[button.getI()][button.getJ()].getKandidaat(new Candidate(button.getKandidaat()));
              if (tmpC.isForceUp() && tmpC.isForceDown()) {
                c.setForceDown(0);
                c.setForceUp(0);
              } else {
                filter.remove(fc);
              }
            }
          }
        }
      }
    }
  }

  private void followChain(ForceChainButton[][] chain, int i, int j, int followUp, int followDown, List<FilterCandidate> filter) {
    List<Candidate> kandidaadid = chain[i][j].getKandidaadid();
    Integer notUp = null, notDown = null;
    for (Candidate c : kandidaadid) {
      if (!c.isForceUp()) {
        notUp = c.getKandidaat();
      }
      if (!c.isForceDown()) {
        notDown = c.getKandidaat();
      }
    }
    if (notUp == null || notDown == null) {
      return;
    }
    Candidate notUpCand = new Candidate(notUp);
    Candidate notDownCand = new Candidate(notDown);
    // rida
    for (int k = 0; k < ruut; k++) {
      if (k != j && chain[i][k] != null) {
        List<Candidate> kan = chain[i][k].getKandidaadid();
        if (isFollowUp(followUp, followDown) && kan.contains(notUpCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notUpCand)).getForceUp(), followUp) && isNotFiltered(i, k, notUpCand, filter)) {
          kan.get(kan.indexOf(notUpCand)).setForceUp(followUp + 1);
          if (kan.size() == 2) {
            followChain(chain, i, k, followUp + 1, followDown, filter);
          }
        }
        if (isFollowDown(followUp, followDown) && kan.contains(notDownCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notDownCand)).getForceDown(), followDown) && isNotFiltered(i, k, notDownCand, filter)) {
          kan.get(kan.indexOf(notDownCand)).setForceDown(followDown + 1);
          if (kan.size() == 2) {
            followChain(chain, i, k, followUp, followDown + 1, filter);
          }
        }
      }
    }
    // veerg
    for (int k = 0; k < ruut; k++) {
      if (k != i && chain[k][j] != null) {
        List<Candidate> kan = chain[k][j].getKandidaadid();
        if (isFollowUp(followUp, followDown) && kan.contains(notUpCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notUpCand)).getForceUp(), followUp) && isNotFiltered(k, j, notUpCand, filter)) {
          kan.get(kan.indexOf(notUpCand)).setForceUp(followUp + 1);
          if (kan.size() == 2) {
            followChain(chain, k, j, followUp + 1, followDown, filter);
          }
        }
        if (isFollowDown(followUp, followDown) && kan.contains(notDownCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notDownCand)).getForceDown(), followDown) && isNotFiltered(k, j, notDownCand, filter)) {
          kan.get(kan.indexOf(notDownCand)).setForceDown(followDown + 1);
          if (kan.size() == 2) {
            followChain(chain, k, j, followUp, followDown + 1, filter);
          }
        }
      }
    }
    // kast
    for (int k = 0; k < ruut; k++) {
      int rida = i / kast * kast + k / kast;
      int veerg = j / kast * kast + k % kast;
      if (rida != i && veerg != j && chain[rida][veerg] != null) {
        List<Candidate> kan = chain[rida][veerg].getKandidaadid();
        if (isFollowUp(followUp, followDown) && kan.contains(notUpCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notUpCand)).getForceUp(), followUp) && isNotFiltered(rida, veerg, notUpCand, filter)) {
          kan.get(kan.indexOf(notUpCand)).setForceUp(followUp + 1);
          if (kan.size() == 2) {
            followChain(chain, rida, veerg, followUp + 1, followDown, filter);
          }
        }
        if (isFollowDown(followUp, followDown) && kan.contains(notDownCand)
            && isNewOrBetterChain(kan.get(kan.indexOf(notDownCand)).getForceDown(), followDown)
            && isNotFiltered(rida, veerg, notDownCand, filter)) {
          kan.get(kan.indexOf(notDownCand)).setForceDown(followDown + 1);
          if (kan.size() == 2) {
            followChain(chain, rida, veerg, followUp, followDown + 1, filter);
          }
        }
      }
    }
  }

  private boolean isNotFiltered(int i, int j, Candidate c, List<FilterCandidate> filter) {
    FilterCandidate fc = new FilterCandidate(i, j, c.getKandidaat());
    return !filter.contains(fc);
  }

  private boolean isNewOrBetterChain(int force, int follow) {
    return force == 0 || force > follow + 1;
  }

  private boolean isFollowDown(int followUp, int followDown) {
    return followUp == 0;
  }

  private boolean isFollowUp(int followUp, int followDown) {
    return followDown == 0;
  }

  /**
   * Multicolors
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level14(List<List<SolverButton>> listid) {
    int diff = 220;
    int level = 14;
    SudokuButton button = level13(listid);
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int kan = 0; kan < ruut; kan++) {
      if (multiColorKandidaadid.contains(new Integer(kan))) {
        List<Integer> v2rvid = new ArrayList<Integer>();
        // teeb listi kõikidest antud kandidaadi erinevatest leiduvatest
        // värvidest
        for (int i = 0; i < ruut; i++) {
          for (int j = 0; j < ruut; j++) {
            if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
              int col = model.getSudokuButtons()[i][j].getColor(kan);
              if (col != -1 && !v2rvid.contains(new Integer(col))) {
                v2rvid.add(new Integer(col));
              }
            }
          }
        }
        Collections.sort(v2rvid);
        for (int mainjava = 0; mainjava < v2rvid.size(); mainjava++) {
          Integer col = v2rvid.get(mainjava);
          List<Integer> teised = new ArrayList<Integer>();
          // paneb teised listi ühekordselt kõik teise värvigrupi
          // värvid, mis on col värvi nupuga seotud
          for (int i = 0; i < ruut; i++) {
            for (int j = 0; j < ruut; j++) {
              if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)
                  && model.getSudokuButtons()[i][j].getColor(kan) == col.intValue()) {
                List<Integer> dep = getDependentColors(i, j, kan);
                for (int java = 0; java < dep.size(); java++) {
                  Integer in = dep.get(java);
                  if (col.intValue() % 2 == 0) {
                    if (in != col && in.intValue() != col.intValue() - 1 && !teised.contains(in)) {
                      teised.add(in);
                    }
                  } else {
                    if (in != col && in.intValue() != col.intValue() + 1 && !teised.contains(in)) {
                      teised.add(in);
                    }
                  }
                }
              }
            }
          }
          Collections.sort(teised);
          for (int i = 1; i < teised.size(); i++) {
            if ((teised.get(i)).intValue() % 2 == 0 && (teised.get(i)).intValue() - (teised.get(i - 1)).intValue() == 1) {
              boolean temp = eemaldatud;
              List<SolverButton> list2 = getColorButtonsSolverButtons(kan, col, level);
              for (int java = 0; java < list2.size(); java++) {
                SolverButton butt = list2.get(java);
                model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
              }
              eemaldatud = true;
              if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                int tempcol = col.intValue();
                if (tempcol % 2 == 0) {
                  tempcol--;
                }
                List<SudokuButton> list3 = getColorButtons(kan, tempcol);
                List<SudokuButton> list3lisa = getColorButtons(kan, teised.get(i - 1));
                for (int java = 0; java < list3lisa.size(); java++) {
                  list3.add(list3lisa.get(java));
                }
                if (!removing || solverSeotud.contains(list3)) {
                  levellist.add(list3);
                  levellist2.add(list2);
                  aste.add(new Integer(level));
                } else {
                  eemaldatud = temp;
                  for (int java = 0; java < list2.size(); java++) {
                    SolverButton butt = list2.get(java);
                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                  }
                }
              } else {
                eemaldatud = temp;
                for (int java = 0; java < list2.size(); java++) {
                  SolverButton butt = list2.get(java);
                  model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                }
              }
              if (eemaldatud) {
                return leitud(listid, levellist, levellist2, "Multicolors", level, diff);
              }
            }
          }
        }
        for (int i = 0; i < ruut; i++) {
          for (int j = 0; j < ruut; j++) {
            if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)
                && model.getSudokuButtons()[i][j].getColor(kan) == -1) {
              List<Integer> dep = new ArrayList<Integer>();
              List<Integer> deptemp = getDependentColors(i, j, kan);
              for (int java = 0; java < deptemp.size(); java++) {
                Integer in = deptemp.get(java);
                if (!dep.contains(in)) {
                  dep.add(in);
                }
              }
              if (dep.size() > 1) {
                Collections.sort(dep);
                // m ja n on erinevate värvigruppide värvide
                // indeksid listis dep
                for (int m = 0; m < dep.size(); m++) {
                  for (int n = m + 1; n < dep.size(); n++) {
                    if ((dep.get(n)).intValue() - (dep.get(m)).intValue() != 1
                        || (dep.get(n)).intValue() / 2 == (dep.get(m)).intValue() / 2) {
                      if (getMulticolorDependences(kan, dep.get(m), dep.get(n))) {
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        list2.add(new SolverButton(i, j, kan, level));
                        for (int java = 0; java < list2.size(); java++) {
                          SolverButton butt = list2.get(java);
                          model.getSudokuButtons()[butt.getI()][butt.getJ()].removeKandidaat(butt.getKandidaat());
                        }
                        eemaldatud = true;
                        if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                          int tempcol = (dep.get(m)).intValue();
                          if (tempcol % 2 == 0) {
                            tempcol--;
                          }
                          int tempcol2 = (dep.get(n)).intValue();
                          if (tempcol2 % 2 == 0) {
                            tempcol2--;
                          }
                          List<SudokuButton> list3 = getColorButtons(kan, tempcol);
                          List<SudokuButton> list3lisa = getColorButtons(kan, tempcol2);
                          for (int java = 0; java < list3lisa.size(); java++) {
                            list3.add(list3lisa.get(java));
                          }
                          if (!removing || solverSeotud.contains(list3)) {
                            levellist.add(list3);
                            levellist2.add(list2);
                            aste.add(new Integer(level));
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                        } else {
                          eemaldatud = temp;
                          for (int java = 0; java < list2.size(); java++) {
                            SolverButton butt = list2.get(java);
                            model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                          }
                        }
                        if (eemaldatud) {
                          return leitud(listid, levellist, levellist2, "Multicolors", level, diff);
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }

      }
    }
    return null;
  }

  /**
   * Jellyfish
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level15(List<List<SolverButton>> listid) {
    int diff = 240;
    SudokuButton button = level14(listid);
    int level = 15;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int kan = 0; kan < ruut; kan++) {
      List<List<Integer>> realist = new ArrayList<List<Integer>>();
      List<List<Integer>> veerulist = new ArrayList<List<Integer>>();
      for (int i = 0; i < ruut; i++) {
        List<Integer> l1 = new ArrayList<Integer>();
        List<Integer> l2 = new ArrayList<Integer>();
        for (int j = 0; j < ruut; j++) {
          if (model.getSudokuButtons()[i][j].getNumber().equals(" ") && model.getSudokuButtons()[i][j].getKandidaat(kan)) {
            l1.add(new Integer(j));
          }
          if (model.getSudokuButtons()[j][i].getNumber().equals(" ") && model.getSudokuButtons()[j][i].getKandidaat(kan)) {
            l2.add(new Integer(j));
          }
        }
        realist.add(l1);
        veerulist.add(l2);
      }
      for (int i = 0; i < ruut; i++) {
        for (int j = i; j < ruut; j++) {
          if (j != i) {
            for (int k = j; k < ruut; k++) {
              if (k != j) {
                for (int m = k; m < ruut; m++) {
                  if (m != k) {
                    List<Integer> rl1 = realist.get(i);
                    List<Integer> rl2 = realist.get(j);
                    List<Integer> rl3 = realist.get(k);
                    List<Integer> rl4 = realist.get(m);
                    Set<Integer> set = new HashSet<Integer>();
                    set.addAll(rl1);
                    set.addAll(rl2);
                    set.addAll(rl3);
                    set.addAll(rl4);
                    if (rl1.size() > 1 && rl2.size() > 1 && rl3.size() > 1 && rl4.size() > 1 && set.size() == 4) {
                      // realist veerg
                      List<Integer> l2 = new ArrayList<Integer>();
                      for (int java = 0; java < rl1.size(); java++) {
                        Integer a = rl1.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < rl2.size(); java++) {
                        Integer a = rl2.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < rl3.size(); java++) {
                        Integer a = rl3.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < rl4.size(); java++) {
                        Integer a = rl4.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      if (l2.size() == 4) {
                        boolean bool = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          for (int java = 0; java < l2.size(); java++) {
                            Integer a = l2.get(java);
                            if (l != i && l != j && l != k && l != m && model.getSudokuButtons()[l][a.intValue()].getNumber().equals(" ")
                                && model.getSudokuButtons()[l][a.intValue()].getKandidaat(kan)) {
                              model.getSudokuButtons()[l][a.intValue()].removeKandidaat(kan);
                              list2.add(new SolverButton(l, a, kan, level));
                              bool = true;
                              eemaldatud = true;
                            }
                          }
                        }
                        if (bool) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int java = 0; java < rl1.size(); java++) {
                              Integer a = rl1.get(java);
                              list3.add(model.getSudokuButtons()[i][a.intValue()]);
                            }
                            for (int java = 0; java < rl2.size(); java++) {
                              Integer a = rl2.get(java);
                              list3.add(model.getSudokuButtons()[j][a.intValue()]);
                            }
                            for (int java = 0; java < rl3.size(); java++) {
                              Integer a = rl3.get(java);
                              list3.add(model.getSudokuButtons()[k][a.intValue()]);
                            }
                            for (int java = 0; java < rl4.size(); java++) {
                              Integer a = rl4.get(java);
                              list3.add(model.getSudokuButtons()[m][a.intValue()]);
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Jellyfish", level, diff);
                          }
                        }
                      }
                    }
                    List<Integer> vl1 = veerulist.get(i);
                    List<Integer> vl2 = veerulist.get(j);
                    List<Integer> vl3 = veerulist.get(k);
                    List<Integer> vl4 = veerulist.get(m);
                    set = new HashSet<Integer>();
                    set.addAll(vl1);
                    set.addAll(vl2);
                    set.addAll(vl3);
                    set.addAll(vl4);
                    if (vl1.size() > 1 && vl2.size() > 1 && vl3.size() > 1 && vl4.size() > 1 && set.size() == 4) {
                      // veerulist rida
                      List<Integer> l2 = new ArrayList<Integer>();
                      for (int java = 0; java < vl1.size(); java++) {
                        Integer a = vl1.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < vl2.size(); java++) {
                        Integer a = vl2.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < vl3.size(); java++) {
                        Integer a = vl3.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      for (int java = 0; java < vl2.size(); java++) {
                        Integer a = vl2.get(java);
                        if (!l2.contains(a)) {
                          l2.add(a);
                        }
                      }
                      if (l2.size() == 4) {
                        boolean bool = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          for (int java = 0; java < l2.size(); java++) {
                            Integer a = l2.get(java);
                            if (l != i && l != j && l != k && l != m && model.getSudokuButtons()[a.intValue()][l].getNumber().equals(" ")
                                && model.getSudokuButtons()[a.intValue()][l].getKandidaat(kan)) {
                              model.getSudokuButtons()[a.intValue()][l].removeKandidaat(kan);
                              list2.add(new SolverButton(a, l, kan, level));
                              bool = true;
                              eemaldatud = true;
                            }
                          }
                        }
                        if (bool) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int java = 0; java < vl1.size(); java++) {
                              Integer a = vl1.get(java);
                              list3.add(model.getSudokuButtons()[a.intValue()][i]);
                            }
                            for (int java = 0; java < vl2.size(); java++) {
                              Integer a = vl2.get(java);
                              list3.add(model.getSudokuButtons()[a.intValue()][j]);
                            }
                            for (int java = 0; java < vl3.size(); java++) {
                              Integer a = vl3.get(java);
                              list3.add(model.getSudokuButtons()[a.intValue()][k]);
                            }
                            for (int java = 0; java < vl4.size(); java++) {
                              Integer a = vl4.get(java);
                              list3.add(model.getSudokuButtons()[a.intValue()][m]);
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Jellyfish", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Hidden Triplets
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level16(List<List<SolverButton>> listid) {
    int diff = 300;
    SudokuButton button = level15(listid);
    int level = 16;
    if (button != null) {
      return button;
    }
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(k)) {
            reas++;
            String s = i + "," + l;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas <= 3 && reas >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              int reas2 = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan2)) {
                  reas2++;
                  String s = i + "," + l;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 <= 3 && reas2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String string = tempkoht.get(java);
                      tempkoht2.add(string);
                    }
                    int reas3 = 0;
                    for (int l = 0; l < ruut; l++) {
                      if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan3)) {
                        reas3++;
                        String s = i + "," + l;
                        if (!tempkoht2.contains(s)) {
                          tempkoht2.add(s);
                        }
                      }
                    }
                    if (reas3 <= 3 && reas3 >= 2) {
                      if (tempkoht2.size() == 3) {
                        boolean bool = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            String s = tempkoht2.get(java);
                            int a = Integer.parseInt(s.split(",")[0]);
                            int b = Integer.parseInt(s.split(",")[1]);
                            if (l != k && l != kan2 && l != kan3 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                              model.getSudokuButtons()[a][b].removeKandidaat(l);
                              list2.add(new SolverButton(a, b, l, level));
                              bool = true;
                              eemaldatud = true;
                            }
                          }
                        }
                        if (bool) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int java = 0; java < tempkoht2.size(); java++) {
                              String s = tempkoht2.get(java);
                              int a = Integer.parseInt(s.split(",")[0]);
                              int b = Integer.parseInt(s.split(",")[1]);
                              list3.add(model.getSudokuButtons()[a][b]);
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Hidden triple", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(k)) {
            reas++;
            String s = l + "," + i;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas <= 3 && reas >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              int reas2 = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan2)) {
                  reas2++;
                  String s = l + "," + i;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 <= 3 && reas2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String string = tempkoht.get(java);
                      tempkoht2.add(string);
                    }
                    int reas3 = 0;
                    for (int l = 0; l < ruut; l++) {
                      if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan3)) {
                        reas3++;
                        String s = l + "," + i;
                        if (!tempkoht2.contains(s)) {
                          tempkoht2.add(s);
                        }
                      }
                    }
                    if (reas3 <= 3 && reas3 >= 2) {
                      if (tempkoht2.size() == 3) {
                        boolean bool = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            String s = tempkoht2.get(java);
                            int a = Integer.parseInt(s.split(",")[0]);
                            int b = Integer.parseInt(s.split(",")[1]);
                            if (l != k && l != kan2 && l != kan3 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                              model.getSudokuButtons()[a][b].removeKandidaat(l);
                              list2.add(new SolverButton(a, b, l, level));
                              bool = true;
                              eemaldatud = true;
                            }
                          }
                        }
                        if (bool) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int java = 0; java < tempkoht2.size(); java++) {
                              String s = tempkoht2.get(java);
                              int a = Integer.parseInt(s.split(",")[0]);
                              int b = Integer.parseInt(s.split(",")[1]);
                              list3.add(model.getSudokuButtons()[a][b]);
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Hidden triple", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      int rida = (i / kast) * kast;
      int veerg = (i % kast) * kast;
      for (int k = 0; k < ruut; k++) {
        int kastis = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = rida; l < (rida + kast); l++) {
          for (int m = veerg; m < (veerg + kast); m++) {
            if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
              kastis++;
              String s = l + "," + m;
              if (!koht.contains(s)) {
                koht.add(s);
              }
            }
          }
        }
        if (kastis <= 3 && kastis >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              int kastis2 = 0;
              for (int l = rida; l < (rida + kast); l++) {
                for (int m = veerg; m < (veerg + kast); m++) {
                  if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan2)) {
                    kastis2++;
                    String s = l + "," + m;
                    if (!tempkoht.contains(s)) {
                      tempkoht.add(s);
                    }
                  }
                }
              }
              if (kastis2 <= 3 && kastis2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String string = tempkoht.get(java);
                      tempkoht2.add(string);
                    }
                    int kastis3 = 0;
                    for (int l = rida; l < (rida + kast); l++) {
                      for (int m = veerg; m < (veerg + kast); m++) {
                        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan3)) {
                          kastis3++;
                          String s = l + "," + m;
                          if (!tempkoht2.contains(s)) {
                            tempkoht2.add(s);
                          }
                        }
                      }
                    }
                    if (kastis3 <= 3 && kastis3 >= 2) {
                      if (tempkoht2.size() == 3) {
                        boolean bool = false;
                        boolean temp = eemaldatud;
                        List<SolverButton> list2 = new ArrayList<SolverButton>();
                        for (int l = 0; l < ruut; l++) {
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            String s = tempkoht2.get(java);
                            int a = Integer.parseInt(s.split(",")[0]);
                            int b = Integer.parseInt(s.split(",")[1]);
                            if (l != k && l != kan2 && l != kan3 && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                              model.getSudokuButtons()[a][b].removeKandidaat(l);
                              list2.add(new SolverButton(a, b, l, level));
                              bool = true;
                              eemaldatud = true;
                            }
                          }
                        }
                        if (bool) {
                          if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                            List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                            for (int java = 0; java < tempkoht2.size(); java++) {
                              String s = tempkoht2.get(java);
                              int a = Integer.parseInt(s.split(",")[0]);
                              int b = Integer.parseInt(s.split(",")[1]);
                              list3.add(model.getSudokuButtons()[a][b]);
                            }
                            if (!removing || solverSeotud.contains(list3)) {
                              levellist.add(list3);
                              levellist2.add(list2);
                              aste.add(new Integer(level));
                            } else {
                              eemaldatud = temp;
                              for (int java = 0; java < list2.size(); java++) {
                                SolverButton butt = list2.get(java);
                                model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                              }
                            }
                          } else {
                            eemaldatud = temp;
                            for (int java = 0; java < list2.size(); java++) {
                              SolverButton butt = list2.get(java);
                              model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                            }
                          }
                          if (eemaldatud) {
                            return leitud(listid, levellist, levellist2, "Hidden triple", level, diff);
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * Hidden Quads
   * 
   * @return leitud nupp või null kui ei leitud
   */
  public SudokuButton level13(List<List<SolverButton>> listid) {
    SudokuButton button = level12(listid);
    if (button != null) {
      return button;
    }
    int level = 13;
    int diff = 200;
    boolean eemaldatud = false;
    List<List<SudokuButton>> levellist = new ArrayList<List<SudokuButton>>();
    List<List<SolverButton>> levellist2 = new ArrayList<List<SolverButton>>();
    for (int i = 0; i < ruut; i++) {
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(k)) {
            reas++;
            String s = i + "," + l;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas <= 4 && reas >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                tempkoht.add(koht.get(java));
              }
              int reas2 = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan2)) {
                  reas2++;
                  String s = i + "," + l;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 <= 4 && reas2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      tempkoht2.add(tempkoht.get(java));
                    }
                    int reas3 = 0;
                    for (int l = 0; l < ruut; l++) {
                      if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan3)) {
                        reas3++;
                        String s = i + "," + l;
                        if (!tempkoht2.contains(s)) {
                          tempkoht2.add(s);
                        }
                      }
                    }
                    if (reas3 <= 4 && reas3 >= 2) {
                      for (int kan4 = kan3; kan4 < ruut; kan4++) {
                        if (kan4 != kan3) {
                          List<String> tempkoht3 = new ArrayList<String>();
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            tempkoht3.add(tempkoht2.get(java));
                          }
                          int reas4 = 0;
                          for (int l = 0; l < ruut; l++) {
                            if (model.getSudokuButtons()[i][l].getNumber().equals(" ") && model.getSudokuButtons()[i][l].getKandidaat(kan4)) {
                              reas4++;
                              String s = i + "," + l;
                              if (!tempkoht3.contains(s)) {
                                tempkoht3.add(s);
                              }
                            }
                          }
                          if (reas4 <= 4 && reas4 >= 2) {
                            if (tempkoht3.size() == 4) {
                              boolean bool = false;
                              boolean temp = eemaldatud;
                              List<SolverButton> list2 = new ArrayList<SolverButton>();
                              for (int l = 0; l < ruut; l++) {
                                for (int java = 0; java < tempkoht3.size(); java++) {
                                  String s = tempkoht3.get(java);
                                  int a = Integer.parseInt(s.split(",")[0]);
                                  int b = Integer.parseInt(s.split(",")[1]);
                                  if (l != k && l != kan2 && l != kan3 && l != kan4
                                      && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                      && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                                    model.getSudokuButtons()[a][b].removeKandidaat(l);
                                    list2.add(new SolverButton(a, b, l, level));
                                    bool = true;
                                    eemaldatud = true;
                                  }
                                }
                              }
                              if (bool) {
                                if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                                  for (int java = 0; java < tempkoht3.size(); java++) {
                                    String s = tempkoht3.get(java);
                                    int a = Integer.parseInt(s.split(",")[0]);
                                    int b = Integer.parseInt(s.split(",")[1]);
                                    list3.add(model.getSudokuButtons()[a][b]);
                                  }
                                  if (!removing || solverSeotud.contains(list3)) {
                                    levellist.add(list3);
                                    levellist2.add(list2);
                                    aste.add(new Integer(level));
                                  } else {
                                    eemaldatud = temp;
                                    for (int java = 0; java < list2.size(); java++) {
                                      SolverButton butt = list2.get(java);
                                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                    }
                                  }
                                } else {
                                  eemaldatud = temp;
                                  for (int java = 0; java < list2.size(); java++) {
                                    SolverButton butt = list2.get(java);
                                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                  }
                                }
                                if (eemaldatud) {
                                  return leitud(listid, levellist, levellist2, "Hidden quad", level, diff);
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      for (int k = 0; k < ruut; k++) {
        int reas = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = 0; l < ruut; l++) {
          if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(k)) {
            reas++;
            String s = l + "," + i;
            if (!koht.contains(s)) {
              koht.add(s);
            }
          }
        }
        if (reas <= 4 && reas >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                String string = koht.get(java);
                tempkoht.add(string);
              }
              int reas2 = 0;
              for (int l = 0; l < ruut; l++) {
                if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan2)) {
                  reas2++;
                  String s = l + "," + i;
                  if (!tempkoht.contains(s)) {
                    tempkoht.add(s);
                  }
                }
              }
              if (reas2 <= 4 && reas2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      String string = tempkoht.get(java);
                      tempkoht2.add(string);
                    }
                    int reas3 = 0;
                    for (int l = 0; l < ruut; l++) {
                      if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan3)) {
                        reas3++;
                        String s = l + "," + i;
                        if (!tempkoht2.contains(s)) {
                          tempkoht2.add(s);
                        }
                      }
                    }
                    if (reas3 <= 4 && reas3 >= 2) {
                      for (int kan4 = kan3; kan4 < ruut; kan4++) {
                        if (kan4 != kan3) {
                          List<String> tempkoht3 = new ArrayList<String>();
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            String string = tempkoht2.get(java);
                            tempkoht3.add(string);
                          }
                          int reas4 = 0;
                          for (int l = 0; l < ruut; l++) {
                            if (model.getSudokuButtons()[l][i].getNumber().equals(" ") && model.getSudokuButtons()[l][i].getKandidaat(kan4)) {
                              reas4++;
                              String s = l + "," + i;
                              if (!tempkoht3.contains(s)) {
                                tempkoht3.add(s);
                              }
                            }
                          }
                          if (reas4 <= 4 && reas4 >= 2) {
                            if (tempkoht3.size() == 4) {
                              boolean bool = false;
                              boolean temp = eemaldatud;
                              List<SolverButton> list2 = new ArrayList<SolverButton>();
                              for (int l = 0; l < ruut; l++) {
                                for (int java = 0; java < tempkoht3.size(); java++) {
                                  String s = tempkoht3.get(java);
                                  int a = Integer.parseInt(s.split(",")[0]);
                                  int b = Integer.parseInt(s.split(",")[1]);
                                  if (l != k && l != kan2 && l != kan3 && l != kan4
                                      && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                      && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                                    model.getSudokuButtons()[a][b].removeKandidaat(l);
                                    list2.add(new SolverButton(a, b, l, level));
                                    bool = true;
                                    eemaldatud = true;
                                  }
                                }
                              }
                              if (bool) {
                                if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                                  for (int java = 0; java < tempkoht3.size(); java++) {
                                    String s = tempkoht3.get(java);
                                    int a = Integer.parseInt(s.split(",")[0]);
                                    int b = Integer.parseInt(s.split(",")[1]);
                                    list3.add(model.getSudokuButtons()[a][b]);
                                  }
                                  if (!removing || solverSeotud.contains(list3)) {
                                    levellist.add(list3);
                                    levellist2.add(list2);
                                    aste.add(new Integer(level));
                                  } else {
                                    eemaldatud = temp;
                                    for (int java = 0; java < list2.size(); java++) {
                                      SolverButton butt = list2.get(java);
                                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                    }
                                  }
                                } else {
                                  eemaldatud = temp;
                                  for (int java = 0; java < list2.size(); java++) {
                                    SolverButton butt = list2.get(java);
                                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                  }
                                }
                                if (eemaldatud) {
                                  return leitud(listid, levellist, levellist2, "Hidden quad", level, diff);
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      int rida = (i / kast) * kast;
      int veerg = (i % kast) * kast;
      for (int k = 0; k < ruut; k++) {
        int kastis = 0;
        List<String> koht = new ArrayList<String>();
        for (int l = rida; l < (rida + kast); l++) {
          for (int m = veerg; m < (veerg + kast); m++) {
            if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(k)) {
              kastis++;
              String s = l + "," + m;
              if (!koht.contains(s)) {
                koht.add(s);
              }
            }
          }
        }
        if (kastis <= 4 && kastis >= 2) {
          for (int kan2 = k; kan2 < ruut; kan2++) {
            if (kan2 != k) {
              List<String> tempkoht = new ArrayList<String>();
              for (int java = 0; java < koht.size(); java++) {
                tempkoht.add(koht.get(java));
              }
              int kastis2 = 0;
              for (int l = rida; l < (rida + kast); l++) {
                for (int m = veerg; m < (veerg + kast); m++) {
                  if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan2)) {
                    kastis2++;
                    String s = l + "," + m;
                    if (!tempkoht.contains(s)) {
                      tempkoht.add(s);
                    }
                  }
                }
              }
              if (kastis2 <= 4 && kastis2 >= 2) {
                for (int kan3 = kan2; kan3 < ruut; kan3++) {
                  if (kan3 != kan2) {
                    List<String> tempkoht2 = new ArrayList<String>();
                    for (int java = 0; java < tempkoht.size(); java++) {
                      tempkoht2.add(tempkoht.get(java));
                    }
                    int kastis3 = 0;
                    for (int l = rida; l < (rida + kast); l++) {
                      for (int m = veerg; m < (veerg + kast); m++) {
                        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan3)) {
                          kastis3++;
                          String s = l + "," + m;
                          if (!tempkoht2.contains(s)) {
                            tempkoht2.add(s);
                          }
                        }
                      }
                    }
                    if (kastis3 <= 4 && kastis3 >= 2) {
                      for (int kan4 = kan3; kan4 < ruut; kan4++) {
                        if (kan4 != kan3) {
                          List<String> tempkoht3 = new ArrayList<String>();
                          for (int java = 0; java < tempkoht2.size(); java++) {
                            tempkoht3.add(tempkoht2.get(java));
                          }
                          int kastis4 = 0;
                          for (int l = rida; l < (rida + kast); l++) {
                            for (int m = veerg; m < (veerg + kast); m++) {
                              if (model.getSudokuButtons()[l][m].getNumber().equals(" ")
                                  && model.getSudokuButtons()[l][m].getKandidaat(kan4)) {
                                kastis4++;
                                String s = l + "," + m;
                                if (!tempkoht3.contains(s)) {
                                  tempkoht3.add(s);
                                }
                              }
                            }
                          }
                          if (kastis4 <= 4 && kastis4 >= 2) {
                            if (tempkoht3.size() == 4) {
                              boolean bool = false;
                              boolean temp = eemaldatud;
                              List<SolverButton> list2 = new ArrayList<SolverButton>();
                              for (int l = 0; l < ruut; l++) {
                                for (int java = 0; java < tempkoht3.size(); java++) {
                                  String s = tempkoht3.get(java);
                                  int a = Integer.parseInt(s.split(",")[0]);
                                  int b = Integer.parseInt(s.split(",")[1]);
                                  if (l != k && l != kan2 && l != kan3 && l != kan4
                                      && model.getSudokuButtons()[a][b].getNumber().equals(" ")
                                      && model.getSudokuButtons()[a][b].getKandidaat(l)) {
                                    model.getSudokuButtons()[a][b].removeKandidaat(l);
                                    list2.add(new SolverButton(a, b, l, level));
                                    bool = true;
                                    eemaldatud = true;
                                  }
                                }
                              }
                              if (bool) {
                                if (!removing || (!listid.contains(list2) && sammud.contains(list2))) {
                                  List<SudokuButton> list3 = new ArrayList<SudokuButton>();
                                  for (int java = 0; java < tempkoht3.size(); java++) {
                                    String s = tempkoht3.get(java);
                                    int a = Integer.parseInt(s.split(",")[0]);
                                    int b = Integer.parseInt(s.split(",")[1]);
                                    list3.add(model.getSudokuButtons()[a][b]);
                                  }
                                  if (!removing || solverSeotud.contains(list3)) {
                                    levellist.add(list3);
                                    levellist2.add(list2);
                                    aste.add(new Integer(level));
                                  } else {
                                    eemaldatud = temp;
                                    for (int java = 0; java < list2.size(); java++) {
                                      SolverButton butt = list2.get(java);
                                      model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                    }
                                  }
                                } else {
                                  eemaldatud = temp;
                                  for (int java = 0; java < list2.size(); java++) {
                                    SolverButton butt = list2.get(java);
                                    model.getSudokuButtons()[butt.getI()][butt.getJ()].restoreKandidaat(butt.getKandidaat());
                                  }
                                }
                                if (eemaldatud) {
                                  return leitud(listid, levellist, levellist2, "Hidden quad", level, diff);
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    return null;
  }

  /**
   * @return Tagastab astme korraliku listina
   */
  private String printAste() {
    StringBuffer s = new StringBuffer();
    for (int index = 0; index < aste.size(); index++) {
      Integer in = aste.get(index);
      s.append(in);
      s.append(", ");
    }
    return s.toString();
  }

  /**
   * Üritab eemaldada üleliigsed sammud
   * 
   * @param button
   * @return
   */
  private int removeExtra(SudokuButton button) {
    removing = true;
    if (config.isDebug() && !model.isGenerating()) {
      Config.log("removing... aste: " + printAste() + " tehnikad: " + tehnikad.size());
    }
    List<List<SolverButton>> sammud = new ArrayList<List<SolverButton>>();
    List<Integer> tmp = new ArrayList<Integer>();
    for (int index = 0; index < aste.size(); index++) {
      Integer integer = aste.get(index);
      tmp.add(integer);
    }
    int max = maxtehnika;
    solverSeotud = button.getSeotud();
    for (int i = this.sammud.size() - 1; i >= 0; i--) {
      maxtehnika = 0;
      if (!tehnikad.get(i).equals("Hidden single") && !tehnikad.get(i).equals("Single")) {
        if (config.isDebug() && !model.isGenerating()) {
          Config.log(tehnikad.get(i) + "\t\t");
        }
        List<SolverButton> list = this.sammud.get(i);
        resetAllKandidaadid();
        setDefaultKandidaadid();
        sammud.add(this.sammud.get(i));
        SudokuButton button2 = level17(sammud);
        if (button.equals(button2) && aste.size() <= tmp.size() - sammud.size() && maxtehnika == max) {
          this.sammud.remove(i);
          tehnikad.remove(i);
          button.getSeotud().remove(i);
          if (config.isDebug() && !model.isGenerating()) {
            Config.log("success aste:" + printAste() + " tmp:" + tmp + " maxtehnika:" + maxtehnika + " max:" + max + " i:" + button2.getI()
                + " j: " + button2.getJ());
          }
          if (config.isDebug() && !model.isGenerating()) {
            for (int java = 0; java < list.size(); java++) {
              SolverButton b = list.get(java);
              Config.log("\t\t\t\ti: " + (b.getI() + 1) + " j: " + (b.getJ() + 1) + " k: " + (b.getKandidaat() + 1) + "; ");
            }
          }
        } else {
          sammud.remove(sammud.size() - 1);
          if (button2 != null) {
            if (config.isDebug() && !model.isGenerating()) {
              Config.log("failure aste:" + printAste() + " tmp: " + tmp + " maxtehnika:" + maxtehnika + " max:" + max + " i:"
                  + button2.getI() + " j: " + button2.getJ());
            }
          } else {
            if (config.isDebug() && !model.isGenerating()) {
              Config.log("failure aste:" + printAste() + " tmp: " + tmp + " maxtehnika:" + maxtehnika + " max:" + max + " i: - j: -");
            }
          }
          if (config.isDebug() && !model.isGenerating()) {
            for (int java = 0; java < list.size(); java++) {
              SolverButton b = list.get(java);
              Config.log("\t\t\t\ti: " + (b.getI() + 1) + " j: " + (b.getJ() + 1) + " k: " + (b.getKandidaat() + 1) + "; ");
            }
          }
        }
      }
    }
    maxtehnika = max;
    button.setTehnikad(tehnikad);
    removing = false;
    return aste.size();
  }

  /**
   * Nulld värviseosed. for (int i = 0; i < ruut; i++) { for (int j = 0; j <
   * ruut; j++) { if (model.getSudokuButtons()[i][j].getNumber().equals(" "))
   * model.getSudokuButtons()[i][j].setColors(new int[ruut]); } }
   */
  private void resetAllColors() {
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
          model.getSudokuButtons()[i][j].setColors(new int[ruut]);
        }
      }
    }
  }

  /**
   * Nullib kõik kandidaadid
   */
  private void resetAllKandidaadid() {
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        model.getSudokuButtons()[i][j].setKandidaadid(new boolean[ruut]);
      }
    }
  }

  /**
   * Nullib kõik sudokubuttonite seosed
   */
  private void resetAllSeotud() {
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        model.getSudokuButtons()[i][j].resetSeotud();
      }
    }
  }

  /**
   * seab nupu [ali,alj] kandidaadi kan värviks col ja käib sellega kaasnevad
   * nupud läbi ning vajadusel kutsub iseennast välja
   * 
   * @param ali
   * @param alj
   * @param kan
   * @param col
   */
  private void setColors(int ali, int alj, int kan, int col) {
    model.getSudokuButtons()[ali][alj].setColor(kan, col);
    if (col % 2 == 0) {
      col--;
    } else {
      col++;
    }
    int rida = (ali / kast) * kast;
    int veerg = (alj / kast) * kast;
    int reas = 0;
    int teinei = 0;
    int teinej = 0;
    boolean leiti = false;
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[ali][l].getNumber().equals(" ") && model.getSudokuButtons()[ali][l].getKandidaat(kan)) {
        reas++;
        if (model.getSudokuButtons()[ali][l].getColor(kan) == -1) {
          leiti = true;
          teinei = ali;
          teinej = l;
        }
      }
    }
    if (reas == 2 && leiti) {
      setColors(teinei, teinej, kan, col);

    }
    leiti = false;
    int veerus = 0;
    for (int l = 0; l < ruut; l++) {
      if (model.getSudokuButtons()[l][alj].getNumber().equals(" ") && model.getSudokuButtons()[l][alj].getKandidaat(kan)) {
        veerus++;
        if (model.getSudokuButtons()[l][alj].getColor(kan) == -1) {
          leiti = true;
          teinei = l;
          teinej = alj;
        }
      }
    }
    if (veerus == 2 && leiti) {
      setColors(teinei, teinej, kan, col);
    }
    leiti = false;
    int kastis = 0;
    for (int l = rida; l < (rida + kast); l++) {
      for (int m = veerg; m < (veerg + kast); m++) {
        if (model.getSudokuButtons()[l][m].getNumber().equals(" ") && model.getSudokuButtons()[l][m].getKandidaat(kan)) {
          kastis++;
          if (model.getSudokuButtons()[l][m].getColor(kan) == -1) {
            leiti = true;
            teinei = l;
            teinej = m;
          }
        }
      }
    }
    if (kastis == 2 && leiti) {
      setColors(teinei, teinej, kan, col);
    }
  }

  /**
   * Algväärtustab kõikide tühjade kastide kandidaadid single loogikat kasutades
   */
  private void setDefaultKandidaadid() {
    aste = new ArrayList<Integer>();
    for (int i = 0; i < ruut; i++) {
      for (int j = 0; j < ruut; j++) {
        if (model.getSudokuButtons()[i][j].getNumber().equals(" ")) {
          for (int k = 0; k < ruut; k++) {
            try {
              int a = Integer.parseInt(model.getSudokuButtons()[i][k].getNumber()) - 1;
              model.getSudokuButtons()[i][j].removeKandidaat(a);
            } catch (Exception er) {
            }
            try {
              int a = Integer.parseInt(model.getSudokuButtons()[k][j].getNumber()) - 1;
              model.getSudokuButtons()[i][j].removeKandidaat(a);
            } catch (Exception er) {
            }
          }
          int rida = 0;
          int veerg = 0;
          if (i > (kast - 1) && i < (kast * 2)) {
            rida = kast;
          }
          if (i > (kast * 2 - 1) && i < (kast * 3)) {
            rida = kast * 2;
          }
          if (i > (kast * 3 - 1) && i < (kast * 4)) {
            rida = kast * 3;
          }
          if (j > (kast - 1) && j < (kast * 2)) {
            veerg = kast;
          }
          if (j > (kast * 2 - 1) && j < (kast * 3)) {
            veerg = kast * 2;
          }
          if (j > (kast * 3 - 1) && j < (kast * 4)) {
            veerg = kast * 3;
          }
          for (int k = rida; k < (rida + kast); k++) {
            for (int l = veerg; l < (veerg + kast); l++) {
              try {
                int a = Integer.parseInt(model.getSudokuButtons()[k][l].getNumber()) - 1;
                model.getSudokuButtons()[i][j].removeKandidaat(a);
              } catch (Exception er) {
              }
            }
          }
        }
      }
    }
  }

  public void setMaxtehnika(int maxtehnika) {
    this.maxtehnika = maxtehnika;
  }

  public SudokuButton solve() {
    if (config.isDebug() && !model.isGenerating()) {
      Config.log("starting solving");
    }
    SudokuButton button = level17(null);
    if (button != null) {
      removeExtra(button);
      if (config.isDebug() && !model.isGenerating()) {
        Config.log("solver max " + maxtehnika);
      }
      return button;
    }
    return null;
  }

  /**
   * Tagastab listi kõikidest antud nupuga seotud nuppudest, kuhu saab panna
   * common kandidaadi
   * 
   * @param i
   * @param j
   * @param common
   * @return
   */
  private List<Point> xyDependences(int i, int j, int common) {
    List<Point> list = new ArrayList<Point>();
    for (int k = 0; k < ruut; k++) {
      if (k != j && model.getSudokuButtons()[i][k].getNumber().equals(" ") && model.getSudokuButtons()[i][k].getKandidaat(common)) {
        Point point = new Point(i, k);
        if (!list.contains(point)) {
          list.add(point);
        }
      }
      if (k != i && model.getSudokuButtons()[k][j].getNumber().equals(" ") && model.getSudokuButtons()[k][j].getKandidaat(common)) {
        Point point = new Point(k, j);
        if (!list.contains(point)) {
          list.add(point);
        }
      }
    }
    int rida = (i / kast) * kast;
    int veerg = (j / kast) * kast;
    for (int k = rida; k < (rida + kast); k++) {
      for (int l = veerg; l < (veerg + kast); l++) {
        if (k != i && l != j && model.getSudokuButtons()[k][l].getNumber().equals(" ")
            && model.getSudokuButtons()[k][l].getKandidaat(common)) {
          Point point = new Point(k, l);
          if (!list.contains(point)) {
            list.add(point);
          }
        }
      }
    }
    return list;
  }
}
